関連する問題
広告表示の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 も更新)
実装タスク
受け入れ条件
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構成ではデバッグトークン設定が必要(実装時に動作確認すること)
将来拡張: 同じ仕組みで他の機能フラグ(キルスイッチ等)にも転用できる
関連する問題
広告表示のON/OFFは
LocalPackage/Sources/HometeDomain/Advertisement/AdDisplayPolicy.swiftのAdDisplayPolicy.isEnabled(ハードコード定数、現在false)で決まっている。そのため広告の有効化・無効化のたびにアプリのリリース(App Store審査)が必要になっている。提案する解決策
Firebase Remote Config のフラグで、広告表示のON/OFFをアプリ更新なしで切り替えられるようにする。
ビジネス価値: 障害・収益影響への即応、リリースと広告運用の切り離し。実装コストは小さく(SDK追加 + Client1つ)、優先度はP1相当。
要件
ads_enabled(Bool)false(現状の1.0.0の挙動と同じ。取得できないときは広告を出さない安全側に倒す)AdDisplayPolicy.isEnabledとの関係: 置き換える。ハードコード定数isEnabledは廃止し、Remote Configの値(未取得時はデフォルトfalse)を使う。shouldShowAds(isPremium:isEnabled:)の判定式(isEnabled && !isPremium)と、プレミアム加入者は広告非表示という既存仕様は変えないminimumFetchInterval: Release は既定の12時間、Debug/Stg は 0 秒(切り替え確認しやすくするため)RemoteConfigClientプロトコル(HometeDomain/Dependencies/)+.previewValue、.liveValueはHometeInfrastructureに実装。AppDependenciesに追加する。Viewから直接 Firebase SDK を触らないhomete-ios-dev-e3ef7)/ prod(homete-ios-dev)の両Firebaseプロジェクトでads_enabledを作成・公開する。prod の初期値はfalse(現状維持)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失敗時のフォールバック)AdDisplayPolicyから定数isEnabledを廃止し、Remote Configの値を判定に使う形へ変更。広告表示箇所(BottomAdBanner呼び出し側、AdsSetupUseCaseなど)の参照を追従shouldShowAdsの組み合わせ(enabled/premium)、Remote Config値が未取得・取得済み・fetch失敗のときの挙動(RemoteConfigClientをモックして検証)ads_enabledを作成・公開(運用手順。手順をdoc/に記載)#Previewを触る場合は.claude/rules/prefire-preview.mdに従う受け入れ条件
ads_enabled=trueを公開し、アプリを再起動すると(非プレミアムユーザーに)広告が表示されるads_enabled=falseを公開し、再起動すると広告が表示されないads_enabledの値によらず広告が表示されないfalse)make test-packagesが通る代替案
AdDisplayPolicy.isEnabledとRemote ConfigのAND: 「コード側で恒久的に止める」余地は残るが二重管理になり、審査なしで有効化できるという目的が果たせない。置き換えを推奨その他の情報
RemoteConfigClientの基盤部分が共通になる。先に着手した側が基盤を入れ、もう一方はその PR のマージ後に着手するHometeDomain/Advertisement/(AdType, BannerType, AdsSetupUseCase, AdDisplayPolicy)、HometeInfrastructure/Advertisement/、HometeUI/Components/Advertisement/(BottomAdBanner, RemoveAdsPromotionLink)、AppRoot/Dependency/Impl/ImplMobileAdsClient.swift、HometeDomain/Dependencies/MobileAdsClient.swift