phaser4-game-ad-integration について
phaser4-game-ad-integration は、TypeScript、Vite、Capacitor を使う Phaser 4 プロジェクトで AppLovin MAX 広告を導入するためのスキルです。モバイル広告を実装する開発者向けに、公式 Cordova プラグイン、非ブロッキング動作、ライフサイクル、再試行、検証の方針を定めます。
主な機能
- 01公式 AppLovin MAX Cordova プラグインの導入
- 02Web とミニゲーム向け no-op 境界
- 03非ブロッキング初期化・表示契約の定義
- 04広告枠ごとの状態と再試行の管理
- 05SDK 初期化とプライバシーフローの分離
- 06プラットフォームテストとコンプライアンス確認
活用シーン
- 01Phaser 4 モバイルプロジェクトへの広告導入
- 02Banner、インタースティシャル、リワード動画の設計
- 03広告初期化と障害復旧ロジックのレビュー
- 04プライバシー対応とプラットフォーム検証の計画
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ weberwang/ phaser-skills --skill phaser4-game-ad-integrationインストール後、Claude Code で/phaser4-game-ad-integrationを入力して読み込まれたか確認します。
同梱ファイルagents/openai.yamlreferences/applovin-max-contract.md
詳細
Phaser 4 AppLovin MAX 広告連携
適用範囲と厳守事項
この Skill は、Phaser 4 + TypeScript/Vite + Capacitor のモバイルプロジェクトにおけるバナー、インタースティシャル、リワード動画広告の機能のみを扱います。メディエーション層には AppLovin MAX を使用し、連携実装には AppLovin が公式にメンテナンスする cordova-plugin-applovin-max を使用します。プラグインは Capacitor の Cordova 互換レイヤーを通じて読み込みます。プロジェクトでは TypeScript 側にビジネス向けファサードと公式プラグイン API のアダプターのみを作成し、Android/iOS 広告プラグインを独自に構築したり、MAX ネイティブ SDK を直接連携したりしません。設定済みの広告ユニットごとに状態を個別に管理します。インタースティシャルとリワード動画はバックグラウンドでサイレントに事前読み込みするだけで、初期化時に広告オブジェクトやビューを積極的に作成しません。プラグイン内部で必要に応じて読み込みリソースを管理します。インタースティシャルとリワード動画の事前読み込み成功は、現在の広告インスタンスオブジェクトの準備完了プロパティを基準とします。loaded コールバックやビジネス phase だけでは、成功を証明できません。全画面広告の表示可否は、インスタンスの準備完了プロパティと既存のビジネス状態を参照して即座に返します。バナーは事前読み込みせず、ビジネス側から表示を要求されたときにのみ作成して読み込みます。バナーに対応し、広告ユニットが有効で、ページでの表示が許可されている場合は、ページの初回フレームより前に広告領域を確保し、UI レイアウトを完了します。広告の読み込みや表示を待ってはいけません。各広告ユニットは読み込み失敗回数、retry deadline、最大 1 つの再試行 timer を個別に管理しますが、分類、バックオフ、一時停止、再開には共通のルールを適用します。設計、実装、レビューを始める前に、唯一の詳細仕様書であるAppLovin MAX 連携仕様書を必ず読み、記載されている状態、タイミング、失敗時、コンプライアンスのルールに従ってください。
- Phaser Web、ブラウザーのプレビュー、ミニゲームから MAX を直接呼び出したり、ネイティブ広告 SDK を読み込んだりしてはいけません。これらの実行環境では、広告機能は明示的に
unsupported/no-op とし、呼び出し後すぐに返してゲームを続行します。 - iOS と Android では、AppLovin 公式の
cordova-plugin-applovin-maxのみを使用します。実装前に公式 Cordova 統合ドキュメントおよび公式リポジトリを確認し、プラグインのバージョン、Capacitor Cordova 互換レイヤー、Android Gradle、iOS パッケージマネージャーとの互換性を検証してください。互換性がない場合は作業を阻止して報告し、コミュニティ製プラグイン、自作の Capacitor ネイティブプラグイン、ビジネスコードからの MAX SDK 直接呼び出しに切り替えてはいけません。 - この Skill は、プロジェクトの MAX コンソール、広告ネットワークのアカウント、ストアのメタデータ、公開チャネルを自動で設定しません。SDK key と ad unit ID は環境ごとに管理されたビルド設定から、公式プラグインアダプターに注入します。ビジネスソースコード、サンプル、ログ、コミット記録に直接記述してはいけません。広告ネットワークのアカウント認証情報と Ad Review key を Web コードや公開成果物に含めてはいけません。
- 広告の表示は自然な中断点でのみ試みます。呼び出し元は広告の読み込み、ネットワークリクエスト、表示完了を決して待ちません。表示できない場合は、広告ユニットの現在の状態に応じた結果を直ちに返し、シーン切り替え、入力、メインループ、精算処理をブロックしてはいけません。バックグラウンドでの読み込み、読み込み失敗、再試行はサイレントに行い、Toast を表示しません。
- ユーザーが動画広告の表示を要求したときに広告が利用できない場合、または公式プラグインが表示を受け付けた後に
displayFailedコールバックが発生した場合は、共通 UI 層を通じて「動画広告を一時的に利用できません。しばらくしてからもう一度お試しください」という Toast を 1 回表示します。プラグインアダプターから Phaser UI を直接操作してはいけません。また、コールバックが重複しても複数回通知してはいけません。 - SDK 初期化とプライバシーフローは独立して進行します。初期化呼び出し、完了状態、失敗時の再試行は、プライバシーのダイアログ、CMP、ATT を待ちません。プライバシーが未確定、取得失敗、または拒否された場合も、SDK 初期化をブロックしてはいけません。MAX 内蔵の Terms and Privacy Policy Flow は初期化前に明示的に無効にし、同期後の有効なネイティブ設定を確認します。広告サービスは引き続き有効にし、MAX initialize の呼び出しを続けます。広告を無効にしたり初期化を省略したりして、このフローを無効化してはいけません。プライバシーの収集は、プロジェクトで採用しているネイティブ CMP/Google UMP と ATT のエントリーポイントを用いて、独立したタスクで処理します。広告サービスは実際のプライバシー状態を参照し、広告の読み込みと表示に対してのみ privacy gate を確認します。SDK 初期化の成功は公式プラグインの実際の完了コールバックを基準とし、リクエストの受理やプライバシーの結果で代用してはいけません。具体的な設定と機能の境界は詳細仕様書に従ってください。
- 新しい MAX インスタンスを初めて実際に初期化する前に、アダプターは共通エントリーポイントからの初期化要求に基づき、公式プラグインの
setHasUserConsent(false)を手動で呼び出してからinitializeを呼び出します。同じ設定での重複呼び出しは既存のタスクを再利用します。hasUserConsent=falseは広告の禁止を意味しません。これを理由にprivacy-pending/privacy-blockedを返したり、load/show を省略したり、事前読み込みを停止したり、読み込み再試行を一時停止したりしてはいけません。privacy gate は、ほかに実際に適用される条件が満たされていないことのみを表し、広告の利用条件としてhasUserConsent === trueを要求してはいけません。この MAX 設定を、ユーザーが選択を完了したことの確認や、AppsFlyer の同意状態として扱ってはいけません。 - バナーは初期化時の事前読み込みの対象外です。最初に表示が要求されたときにのみネイティブビューを作成して読み込み、呼び出しはすぐに返します。loaded を受け取り、レイアウトが安全で、ビジネス側が引き続き表示を要求している場合に表示します。作成または読み込みに失敗した場合は非表示のまま、独立した共通のバックオフルールに従って再試行します。表示シーンを離れたら表示要求を解除して再試行をキャンセルし、古いコールバックによって再作成または再表示してはいけません。Toast を表示せず、高さを余分に確保せず、読み込みを待ってはいけません。
全体制御への接続
$phaser4-game-workflow-control は、全体状態、リスクゲート、タスク範囲、証跡を管理する唯一のコントロールプレーンです。この分野では、現在の Work Item、凍結済みの Implementation Package、A レベル、パスの範囲内で、案の提示、現状のレビュー、実装を行えます。すべての計画、変更、テスト証跡、阻害事項はコントロールプレーンに登録し、レビューを受ける必要があります。タスク内でインターフェース、パス、検証範囲を調整する場合は Work Item を同時に更新し、並行する別の状態マシンを作成してはいけません。
外部への書き込み、支払い、実機、ストアへの提出、公開、取り消し不能な操作に関わる A4-A6 のアクションは、対象ごとにコントロールプレーンから明示的な承認を得る必要があります。この Skill は、それらのアクションを承認、実行、プッシュしたり、実機での受け入れテストを自動的に開始したりしません。通常のローカル文書、ブリッジコード、ユニットテストは、現在のタスクで許可された範囲内で実行できます。
実装手順
広告 SDK の初期化と独立したプライバシータスクのアプリケーション層での起動は、src/platform/initialize-sdks.ts に統一して接続し、SDK の統一初期化に従ってそれぞれ起動します。MAX の初期化呼び出し、実際の完了コールバック、冪等性を保つ状態、初期化の復旧タスクは同ファイルが管理し、公式プラグインアダプターはネイティブ API の詳細のみをラップします。広告サービスは引き続き、各広告枠の読み込み/表示状態と実行時の復旧タスクを管理します。Scene、Boot/Preload、またはコンストラクターに別の起動経路を設けてはなりません。また、単一ファイルへの集約を理由に、プライバシータスクを MAX 初期化の前提条件にしてはなりません。
プロジェクトで AppsFlyer を使用する場合、同じ統一ファイル内で独立して初期化・起動し、MAX、MAX 内蔵のプライバシーフロー、広告の読み込みを待たせません。また、MAX のコールバック内から起動してはなりません。同様に、MAX も AppsFlyer やアトリビューション結果を待ちません。両者の失敗、タイムアウト、復旧はそれぞれ個別に処理し、相互にキャンセルせず、プラグインが管理する推移的依存関係を重複してインストールまたは初期化しません。
- 現在の Work Item、プロジェクトの TDD/依存関係の機能要件、Capacitor のプラットフォーム状態、公式プラグインのインストール状態を確認します。AppLovin MAX 接続契約に従って、対象範囲、対象外、公開インターフェース、状態の所有権、ライフサイクル、失敗境界を記録します。広告は任意の商用機能であり、Phaser Web のコアループの実行前提条件にしてはなりません。
- 最小限のモジュール案を提出します。内容は、Web/ミニゲーム向け no-op、AppLovin 公式 Cordova プラグイン、共有 TypeScript ビジネスファサードとプラグイン API アダプター、テスト用代替実装です。公式プラグインのリリースバージョン、ライセンス、Android/iOS のサポート、Capacitor との互換方法、コールバックのセマンティクス、プライバシー機能を確認します。コミュニティ製プラグインや独自のネイティブブリッジを代替実装として提案してはなりません。
- プラグインアダプターの契約を確定します。
initialize、preload(slotId)、tryShow(context)、setBannerVisibility(slotId, visible)、isReady(slotId)はすべてノンブロッキング呼び出しとし、構造化された結果を返します。統一初期化ファイルが MAX 初期化コールバックの登録と処理を担い、アダプター層は必要なネイティブ API 呼び出しの詳細のみをラップします。MAX の初期化失敗はfailedに遷移します。明確な一時的障害に対しては、src/platform/initialize-sdks.ts内の MAX 専用タスクが 2/4/8/16/32/64 秒の間隔で継続的にバックオフします。バックグラウンド、オフライン、またはホスト側の条件が満たされていない場合は一時停止し、復帰後に再開します。設定または依存関係のエラーを修正した後は、注入された MAX 専用の再試行エントリーポイントを通じて明示的に復旧します。SDK 初期化の復旧と広告枠の読み込み復旧は分離し、タイマーやカウンターを共有しません。対応プラットフォームでサービスが有効かつプラグイン設定が有効な場合は、プライバシーへの同意、CMP の完了、ATT の許可を呼び出しの前提条件とせず、必ず MAX の初期化を開始します。各広告枠の業務上の状態所有者は 1 つだけとし、ネイティブ形式のオブジェクトは公式プラグイン内部で管理します。初期化の成功後は、有効なすべてのインタースティシャル広告とリワード動画広告のプリロード要求をただちに発行します。実際の読み込みは広告リクエストのプライバシーゲートを通過させます。開始済みの読み込みが失敗した場合は、エラーの種類にかかわらず、成功するまで各広告枠専用の再試行タイマーで継続的にスケジュールします。試行回数に上限は設けません。無効化、削除、またはサービスの破棄によって、該当する広告枠の再試行を終了します。実行ゲートが閉じている間は一時停止のみとします。各広告枠はカウンターと deadline を個別に保持し、同一の2/4/8/16/32/64 秒バックオフ、ジッター、重複排除、バックグラウンド/オフライン時の一時停止と復帰のルールを適用します。ある広告枠のキャンセル、再スケジュール、再試行が、他の広告枠のタイマーに影響してはなりません。 - MAX コンソール、公式プラグインとそのネイティブ依存関係、Capacitor Cordova の互換設定、独立したプライバシータスク(CMP/Google UMP/ATT)、広告枠の設定、テレメトリーそれぞれの責任者を明記します。プライバシータスクは SDK 初期化タスクの前提依存関係にも完了条件にもしてはなりません。固定のメディエーションチャネルは AppLovin、Google AdMob、Mintegral、Pangle、Unity Ads、DT Exchange(Fyber)、Verve(PubNative/HyBid)とします。プラグイン、MAX SDK、アダプターのバージョンの組み合わせは、公式プラグインおよび公式チャネルのドキュメントに記載されている最新の互換範囲に従います。Skill やビジネスコードにバージョン番号を固定で記述せず、プラグインを迂回して MAX SDK を重複して導入してはなりません。
- 自然な中断ポイントで
tryShowを呼び出します。この呼び出しでは、指定された広告枠の現在有効なインスタンスの準備状態と業務スナップショットを読み取り、フォアグラウンドでの読み込みを決して開始しません。対応するリワード動画のhiddenコールバックを受け取った後、広告サービスは単調時計を使って 30 秒間のインタースティシャル保護期間の終了時刻を記録します。保護期間中のインタースティシャルtryShowはただちにrewarded-interstitial-delayを返し、MAX の show を呼び出さず、クールダウンタイマーを作成せず、利用不可の Toast も表示しません。保護期間の終了後、対象広告枠が ready で、すべてのゲートが open であり、自然な中断条件が成立していれば、表示を開始できます。ready でない場合、同じ広告枠が表示中の場合、プライバシーが未確定の場合、ネットワークが利用できない場合、またはプラットフォームが非対応の場合は、ただちに結果を返してゲームを続行します。動画広告が利用できない場合や表示に失敗した場合は、統一 UI 層が構造化された結果/イベントを処理し、利用不可の Toast を 1 回だけ表示します。リワードは対応するrewardedコールバックによってのみ非同期で付与し、冪等性を保ちます。広告を閉じた後、または表示に失敗した後は、対応する全画面広告枠をただちに通知なしでプリロードします。 - Banner を表示できるページに入る際は、現在のプラットフォームの形式、利用可能な幅、安全領域に基づいて予約サイズとコンテンツの inset を決定し、ページの最初のフレームが描画される前に UI レイアウトを完了します。レイアウト計画では広告ビューを作成せず、広告もリクエストしません。Banner を表示する際は予約領域に配置するだけとし、ゲーム UI を調整しません。実際のサイズを安全に収容できない場合は非表示のままとし、次回のページまたは viewport のレイアウトサイクルで処理します。Banner にはネイティブ広告ビューを使用します。業務ロジックが制御するのは表示/非表示のみとし、独自の更新タイマーを作成しません。非表示、バックグラウンドへの移行、またはページで広告表示が許可されていない場合は更新を一時停止し、表示復帰時は契約に従って再開します。ゲームのボタン、ジェスチャー領域、システムの安全領域に重ねてはならず、空のプレースホルダーを読み込み済み広告として扱ってはなりません。
- まず静的レビュー、TypeScript/ネイティブのコンパイル、状態機械の単体テストを完了してから、許可された対象環境でプラットフォーム統合テストを実行します。MAX Test Mode と Mediation Debugger を使用し、チャネルと形式ごとに検証します。
app-ads.txt、iOS SKAdNetwork、Google CMP/TCF、ATT を確認します。単一のネットワークまたは単一の形式の成功を、すべてのテストの合格として扱ってはなりません。 - 候補の diff、インターフェース契約、プラットフォームログ(機密情報をマスキング済み)、失敗時の再試行履歴、検証結果を
$phaser4-game-workflow-controlに提出します。実施していない外部設定、実機、実際の広告配信、公開の手順は、未対応項目として明記します。
最低限の公開契約
共有ファサードは、少なくとも以下のセマンティクスを提供します。具体的なパラメーター名は対象プロジェクトの慣例に合わせて構いませんが、結果を返すタイミングは変更できません。
initialize(config): Promise<InitResult> // 只确认桥接请求受理/初始化状态,不等待广告加载
retryInitialize(): Promise<InitResult> // 转发至共享初始化文件中的 MAX 任务,不绕过退避或配置阻断
preload(slotId): Promise<PreloadResult> // 仅插页/激励后台加载;Banner 返回 format-mismatch
isReady(slotId): ReadyResult // 全屏读取实例就绪属性;Banner 读取加载状态,不创建或加载
tryShow(context): Promise<ShowResult> // 复核实例就绪属性和业务门,通过后才展示
setBannerVisibility(slotId, visible): Promise<BannerVisibilityResult> // 展示时按需创建/加载,立即返回
結果には、少なくとも安定した ok、code、platform、phase、gates と、必要に応じて retryScheduled フィールドを含めます。リワード動画後の 30 秒間の保護期間によってインタースティシャルがスキップされた場合は、rewarded-interstitial-delay と interstitialDelayRemainingMs を返します。業務ロジックの呼び出し元が渡すのは、環境、機能の有効化フラグ、業務上の slotId のみです。公式プラグインアダプターは、環境に応じて SDK key と MAX ad unit ID を解決し、プラグイン API の境界でのみ使用します。プラグインの生の例外、デバイス ID、広告ネットワークのアカウント認証情報、または waterfall の認証情報全体を業務層に渡してはなりません。tryShow が「表示を要求済み」と返しても、表示の成功を意味するわけではありません。
InitResult、PreloadResult、ReadyResult、ShowResult、NativeAdEvent の最小フィールド、プライバシーゲート/結果コード、instanceGeneration/showRequestId の関連付け、イベント重複時の冪等性ルールは、すべて接続契約に従います。
交付审查清单
- 平台边界:Web/小游戏调用为 no-op;Android/iOS 仅通过 AppLovin 官方 Cordova 插件调用 MAX,未引入社区插件、自建原生广告插件或直接 SDK 接入;宿主页面生命周期、Activity/ViewController 和前后台切换已明确。
- 生命周期:初始化幂等;每个已配置广告位持有业务 phase、加载计数、retry deadline 和至多一个加载重试 timer,格式匹配的原生对象由官方插件管理;广告服务额外持有激励视频结束后的 30 秒插页保护截止时间,但不为此创建 timer。所有广告位共享该跨格式保护状态等服务级门,不共享加载重试 timer,不设置跨广告位全屏互斥;实例重建递增
instanceGeneration,展示请求生成唯一showRequestId;成功初始化立刻投递全部启用的插页与激励视频预加载意图,实际加载经过广告请求隐私门,重复调用不会并发请求。 - 原生门:Activity/ViewController provider、前台状态和网络连通性参与初始化调度;privacy readiness 仅参与广告加载与展示,不参与初始化调用、完成判定或重试,也不等于
hasUserConsent。必须覆盖false已设置且无其他阻断时正常加载的路径。phase只表示广告资源/展示阶段,门状态独立计算,不混入 Phaser 场景状态。 - 节奏:插页只在自然中断点展示;匹配的激励视频
hidden事件从其单调时间戳起阻断插页 30 秒,保护期只阻断插页,不阻断 Banner、激励视频、后台预加载或奖励结算。保护期内立即静默返回剩余毫秒数,过期后无需 timer 唤醒即可恢复判定;hidden与displayFailed都会触发对应广告位的后台预加载。 - 就绪判断:全屏广告实例的就绪属性是预加载成功的唯一依据;适配器通过官方 isInterstitialReady/isRewardedAdReady 读取插件内部实例状态,不另存独立 ready 布尔值。loaded 仅触发复核;展示与重试前重新读取,实例不存在、失效或读取失败均视为未就绪;Banner 仍按创建后的加载事件管理,不参与预加载。
- 初始化恢复:共享初始化文件中的 MAX 独立任务最多持有一个初始化请求和一个待执行重试 timer;瞬时失败持续退避,宿主/前台/网络门关闭保留 deadline,隐私状态不暂停初始化重试,恢复时去重调度;配置错误不自动重试。成功、禁用或销毁清理该 SDK 的恢复任务,成功后只投递一次全屏预加载意图,广告请求仍检查隐私门,阻断时保留意图待恢复。
- 失败恢复:每个广告位使用独立加载重试 timer,并遵循同一套退避公式持续重试直到成功,不设次数上限;计数、deadline、timer 引用和 in-flight 标记均按广告位隔离,同一广告位只允许一个待执行 timer。后台或离线时分别暂停,恢复后每个到期广告位最多恢复一次;展示失败独立记录并重新预加载,不进入另一套重试逻辑。
- 用户反馈:后台加载、重试和状态变化保持静默;视频广告展示触发在立即判定不可用或异步
displayFailed时只显示一次本地化不可用 Toast,重复/迟到回调不会重复提示;rewarded-interstitial-delay是预期节奏控制,不显示不可用 Toast。 - Banner:不预加载、不默认创建;首次展示请求创建并加载,创建失败和加载失败共用一个持续退避重试任务;离开展示场景立即取消任务并使旧请求失效,再次进入须重新请求展示;ready 且布局安全后按当前可见请求显示,失败保持隐藏且无 Toast;页面首帧前按平台 Banner 尺寸规则和安全区预留区域,加载、失败、重试与显隐回调不改变内容 inset;实际尺寸只用于验证能否安全放入预留区域,布局不遮挡游戏交互;刷新只有一个所有者,禁止 JS/Phaser 自建刷新 timer。
- 合规与安全:独立隐私任务的 CMP/Google UMP/TCF 配置、MAX 隐私标志、iOS ATT、SKAdNetwork、Google 要求和目标地区规则均有责任人和证据;初始化链路未启用自动隐私弹窗,隐私事件不改写 SDK 初始化状态;SDK key 与广告位来自受控的分环境构建配置并仅供官方插件适配器使用,账号凭证与 Ad Review key 不进入 Web 层,遥测脱敏。
- 验证:每个固定网络均在测试模式或 Mediation Debugger 中单独确认 adapter、加载、展示和官方插件失败回调;检查 MAX waterfall、
app-ads.txt和发布前平台清单。单测还要覆盖官方插件广告事件永不返回时,结算通过 fire-and-forget 仍继续,以及适配器 Promise 只等待本地受理/拒绝、不等待广告事件。
本仓库本次只交付 Skill 指导文件,不新增运行时代码、脚本、SDK 依赖或外部配置。