Skip to content

Feature: Remote Configで広告の表示・非表示を切り替えられるようにする #331

Description

@stotic-dev

関連する問題

広告表示のON/OFFは LocalPackage/Sources/HometeDomain/Advertisement/AdDisplayPolicy.swift の AdDisplayPolicy.isEnabled(ハードコード定数、現在 false)で決まっている。そのため広告の有効化・無効化のたびにアプリのリリース(App Store審査)が必要になっている。

  • 広告配信まわりで障害や不具合(表示崩れ、クラッシュ、審査指摘など)が起きても、審査を待たないと止められない
  • 本番で広告バナーを配信できるようになった際、再開のためだけにリリースが要る
  • 段階的な配信(まず有効化して様子を見て、問題があれば止める)ができない

提案する解決策

Firebase Remote Config のフラグで、広告表示のON/OFFをアプリ更新なしで切り替えられるようにする。

ビジネス価値: 障害・収益影響への即応、リリースと広告運用の切り離し。実装コストは小さく(SDK追加 + Client1つ)、優先度はP1相当。

要件

  • Remote Configパラメータ
    • キー: ads_enabled(Bool)
    • アプリ内デフォルト値: false(現状の1.0.0の挙動と同じ。取得できないときは広告を出さない安全側に倒す)
  • 既存 AdDisplayPolicy.isEnabled との関係: 置き換える。ハードコード定数 isEnabled は廃止し、Remote Configの値(未取得時はデフォルト false)を使う。shouldShowAds(isPremium:isEnabled:) の判定式(isEnabled && !isPremium)と、プレミアム加入者は広告非表示という既存仕様は変えない
  • fetchのタイミング
    • 起動時に fetch を開始する。ただし起動をブロックしない(タイムアウトや失敗でも起動は継続)
    • 起動時に間に合わなかった場合は、前回 activate 済みのキャッシュ値、それも無ければアプリ内デフォルト値を使う
    • 広告表示中に値が切り替わるとレイアウトが崩れるため、反映は fetch 後の次回起動時を基本とする(activate のタイミングは実装時に決定してよい。ただし方針を PR に明記)
    • minimumFetchInterval: Release は既定の12時間、Debug/Stg は 0 秒(切り替え確認しやすくするため)
  • DI: 既存パターンに従い RemoteConfigClient プロトコル(HometeDomain/Dependencies/)+ .previewValue、.liveValue は HometeInfrastructure に実装。AppDependencies に追加する。Viewから直接 Firebase SDK を触らない
  • 環境: stg(homete-ios-dev-e3ef7)/ prod(homete-ios-dev)の両Firebaseプロジェクトで ads_enabled を作成・公開する。prod の初期値は false(現状維持)
  • 権限: Remote Configの編集はFirebaseコンソール権限を持つ運営者のみ。アプリ側にユーザー操作の追加はなし
  • 通知: なし
  • Analytics: 新規イベントは追加しない想定(追加する場合は doc/analytics_events.md も更新)

実装タスク

  • LocalPackage/Package.swift に FirebaseRemoteConfig を追加(必要なモジュールのみ依存させ、doc/multimodules_structure.md を必要に応じ更新)
  • HometeDomain/Dependencies/RemoteConfigClient.swift: プロトコル・.previewValue を定義し AppDependencies に追加
  • HometeInfrastructure に RemoteConfigClient.liveValue を実装(アプリ内デフォルト値 ads_enabled=false、minimumFetchInterval のビルド構成別設定、fetch失敗時のフォールバック)
  • 起動処理で fetch を開始(起動をブロックしない)
  • AdDisplayPolicy から定数 isEnabled を廃止し、Remote Configの値を判定に使う形へ変更。広告表示箇所(BottomAdBanner 呼び出し側、AdsSetupUseCase など)の参照を追従
  • ユニットテスト: shouldShowAds の組み合わせ(enabled/premium)、Remote Config値が未取得・取得済み・fetch失敗のときの挙動(RemoteConfigClient をモックして検証)
  • stg / prod の Firebaseコンソールで ads_enabled を作成・公開(運用手順。手順を doc/ に記載)
  • 置き換え方針・activateタイミングの判断が技術選定に当たる場合は ADR を追加
  • #Preview を触る場合は .claude/rules/prefire-preview.md に従う

受け入れ条件

  • Remote Configで ads_enabled=true を公開し、アプリを再起動すると(非プレミアムユーザーに)広告が表示される
  • ads_enabled=false を公開し、再起動すると広告が表示されない
  • プレミアム加入者は ads_enabled の値によらず広告が表示されない
  • オフライン・fetch失敗・初回起動でも起動が遅延せず、広告は表示されない(デフォルト false)
  • make test-packages が通る

代替案

  • ハードコード定数のままリリースで切り替える: 現状。審査待ちの間、障害に即応できない
  • Firestoreにフラグを持たせる: 自前のリスナー実装・セキュリティルール整備が必要で、Remote Configの方が段階配信・キャッシュ・フォールバックが標準機能で揃う
  • AdDisplayPolicy.isEnabled とRemote ConfigのAND: 「コード側で恒久的に止める」余地は残るが二重管理になり、審査なしで有効化できるという目的が果たせない。置き換えを推奨

その他の情報

  • リポジトリ内に Remote Config の利用実績はなく、SDKの新規追加が必要
  • 依存関係: Feature: Firebase Remote Config による強制アップデート #330(Remote Config による強制アップデート)と、Remote Config SDK の導入および RemoteConfigClient の基盤部分が共通になる。先に着手した側が基盤を入れ、もう一方はその PR のマージ後に着手する
  • 関連コード: HometeDomain/Advertisement/(AdType, BannerType, AdsSetupUseCase, AdDisplayPolicy)、HometeInfrastructure/Advertisement/、HometeUI/Components/Advertisement/(BottomAdBanner, RemoveAdsPromotionLink)、AppRoot/Dependency/Impl/ImplMobileAdsClient.swift、HometeDomain/Dependencies/MobileAdsClient.swift
  • App Check は stg/prod とも強制適用済み。Remote Config の fetch も App Check の対象になり得るため、Debug構成ではデバッグトークン設定が必要(実装時に動作確認すること)
  • 将来拡張: 同じ仕組みで他の機能フラグ(キルスイッチ等)にも転用できる

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions