mcpField
I
implement-in-app-purchases

implement-in-app-purchases

github.com/unity-technologies開発60456 回インストール今日更新
リポジトリ

implement-in-app-purchases について

`com.unity.purchasing`を使ったUnityアプリ内課金の実装スキルです。プロジェクトを確認して新規導入や移行の手順を選び、Unity IAP 5の購入、検証、イベント処理を案内します。

主な機能

  1. 01プロジェクトを確認して導入経路を選択
  2. 02Unity IAP 5の初期化と商品取得
  3. 03保留中・確定済み購入の処理
  4. 04購入の復元と権利状態の確認
  5. 05レシート検証と既存課金の移行

活用シーン

  1. 01Unityプロジェクトへのアプリ内課金追加
  2. 02既存課金からUnity IAP 5への移行
  3. 03レシート検証と購入復元の実装

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/unity-technologies/unity-agent-plugin --skill implement-in-app-purchases

インストール後、Claude Code で/implement-in-app-purchasesを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
api-notes.md
codeless-catalog.md
convert-adapty.md
convert-essentialkit.md
convert-revenuecat.md
convert-unipay.md
migration-v4-to-v5.md
path-add-iap-to-new-project.md
path-convert-native-google-billing.md
path-convert-native-storekit.md
path-implement-iap-d2c.md
platform-notes.md
pre-check.md

詳細

Unity アプリ内課金

名前空間:UnityEngine.Purchasing | セキュリティ:UnityEngine.Purchasing.Security パッケージ:com.unity.purchasing

Unity IAP には、UnityIAPServices.StoreController() → store.Connect() という独自の初期化経路があります。 UnityServices.InitializeAsync() は不要ですが、プロジェクトでほかの UGS サービスを使用している場合は併用できます。Analytics が存在し、InitializeAsync() が呼び出されると、IAP はトランザクションイベントを自動的に送信します。

開始する前に

必ず最初に references/pre-check.md をお読みください。 プロジェクトをスキャンして、サードパーティ製 IAP パッケージ、ネイティブ Google Billing、既存の Unity IAP バージョンを確認し、適切な手順に振り分けます。振り分けが完了するまで、ほかのリファレンスファイルを読んだり、変更を加えたりしないでください。

詳細なリファレンス

リファレンスファイルは必要に応じてお読みください。具体的な API シグネチャ、プラットフォーム拡張の詳細、または移行の対応関係が必要な場合にのみ参照してください。

初期化フロー

  1. UnityIAPServices.StoreController() を使って StoreController を取得します(または DefaultStore()、DefaultProduct()、DefaultPurchase() を使って個別のサービスを取得します)
  2. Connect() を呼び出す前に、必要なイベントをすべて登録します(下記の必須イベント登録を参照)
  3. await store.Connect() を呼び出して、プラットフォームストアに接続します
  4. OnStoreConnected で、store.FetchProducts(List<ProductDefinition>) を呼び出してカタログを読み込みます
  5. OnProductsFetched で、商品を表示および購入できるようになります

初期化には Awake() を使用してください。ほかの Start() メソッドが実行される前に IAP の準備を確実に完了できます。

商品タイプ:ProductType.Consumable、ProductType.NonConsumable、ProductType.Subscription。

商品の取得

商品を List<ProductDefinition> として定義し、store.FetchProducts() に渡します。Apple/Google のストア間で商品 ID が異なる場合は、StoreSpecificIds を使用します。複雑なカタログでは、CatalogProvider を使用して商品セットとストア固有の ID を管理します。

メソッド動作
GetProducts()キャッシュ済みの商品リストを返します(同期処理です。FetchProducts が呼び出されていない場合、情報が古い可能性があります)
FetchProducts()ストアに問い合わせて最新の価格/提供状況を取得し、キャッシュを更新します
GetProductById(id)ID を指定して、キャッシュ済みの商品を 1 つ返します

これらは相互に置き換えられません。GetProducts() の結果を利用する前に、必ず FetchProducts() を呼び出してください。

2 段階の購入フロー

IAP v5 では、保留 → 確定の 2 段階フローが必須です。

  1. store.PurchaseProduct(product) — プラットフォームの購入ダイアログを開始します
  2. OnPurchasePending が発生します — PendingOrder を受け取ります
  3. レシートを検証し、プレイヤーにコンテンツを付与します
  4. store.ConfirmPurchase(pendingOrder) — トランザクションを確定します
  5. OnPurchaseConfirmed が発生します — 基底型の Order を受け取ります。パターンマッチングで、ConfirmedOrder(成功)と FailedOrder(確定失敗)を判別します

コンテンツを付与した後、必ず ConfirmPurchase(pendingOrder) を呼び出してください。 未確定の購入は、購入の消失を防ぐため、次回のアプリ起動時に再配信されます。

重複排除: 同じ購入に対して OnPurchasePending が複数回発生することがあります(例:確定前にアプリを再起動した場合)。コンテンツをすでに付与済みかどうかを必ず確認してください。

消費型アイテム: 確定済みの消費型アイテムの購入は、FetchPurchases から返されません。消費型アイテムの付与状況は、独自に(例:Cloud Save または Economy で)追跡してください。

保留中の購入: Ask-to-Buy(iOS)および Google Play の保留中の購入では、OnPurchaseDeferred が発生します。コンテンツを付与してはいけません。承認後に OnPurchasePending が発生するまで待ってください。

トランザクションの復元

store.RestoreTransactions(callback) は、非消費型アイテムおよびサブスクリプションの購入を再配信します。復元された購入ごとに OnPurchasePending が発生します。

Apple App Store の規約に準拠するには iOS で必須です。「購入を復元」ボタンを追加してください。

Apple の非自動更新サブスクリプションは、RestoreTransactions では復元できません。これらはサーバー側で追跡してください。

レシートの検証

プラットフォーム方法
Google PlayCrossPlatformValidator と GooglePlayTangle.Data() を使用します。ローカル検証に対応しています
Apple(StoreKit 2)ローカル検証は何も行いません。サーバー側で検証するには order.Info.Apple?.jwsRepresentation を使用します

Unity エディターで Services > In-App Purchasing > Receipt Validation Obfuscator を選択し、タンゴルデータを生成します。

エンタイトルメントの確認

Order がなく、特定の商品について状態を確認したい場合に使用します(v4 の product.hasReceipt に相当します)。すでに Order がある場合は、代わりにその型を確認してください。PendingOrder は EntitledUntilConsumed(消費型アイテム)または EntitledButNotFinished(非消費型アイテム/サブスクリプション)に対応し、ConfirmedOrder は FullyEntitled に対応します。

store.CheckEntitlement(product) を呼び出し、store.OnCheckEntitlement を処理します。entitlement.Status == EntitlementStatus.FullyEntitled を確認してください。

EntitlementStatus の値:FullyEntitled、EntitledUntilConsumed、EntitledButNotFinished、NotEntitled、Unknown。

既存の購入の取得

store.FetchPurchases() は、ストアから現在の購入をすべて取得します。アプリ起動時に便利です。

メソッド動作
GetPurchases()キャッシュ済みの購入リストを返します
FetchPurchases()ストアに問い合わせて現在の購入を取得し、キャッシュ済みのリストを上書きします

FetchPurchases() は、呼び出すたびにキャッシュ済みのリスト全体を置き換えます。再取得されるのは非消費型アイテムとサブスクリプションのみです。確定済みの消費型アイテムは返されません(上記の「2 段階の購入フロー」を参照)。

サブスクリプション情報

サブスクリプション情報は IPurchasedProductInfo にあり、order.Info.PurchasedProductInfo 経由でアクセスします。CartItem にはありません(CartItem が持つのは Product と Quantity のみです)。

IsSubscribed() は bool ではなく、Result 列挙型(True/False/Unsupported)を返します。null 安全な比較には == Result.True を使用してください。

必須イベントのサブスクリプション

成功イベントと失敗イベントの両方に必ずサブスクライブしてください。 失敗イベントにサブスクライブしないと、実行時警告が発生します。

呼び出し成功イベント失敗イベント(必須)
FetchProducts()OnProductsFetchedOnProductsFetchFailed
FetchPurchases()OnPurchasesFetchedOnPurchasesFetchFailed
Connect()OnStoreConnectedOnStoreDisconnected
PurchaseProduct()OnPurchasePendingOnPurchaseFailed
CheckEntitlement()OnCheckEntitlement—

必ず OnPurchaseDeferred にサブスクライブしてください。このイベントは Ask-to-Buy(iOS)および Google Play の保留中の購入で発生します。サブスクライブしないと、保留中の購入は通知されずに破棄されます。

Connect() を呼び出す前にイベントにサブスクライブしてください。前回のセッションから保留中の購入があると、直ちにイベントが発生することがあります。

失敗の説明に関するプロパティ名

これらのプロパティ名は互換性がありません。誤った名前を使用すると CS1061 が発生します。

型フィールドプロパティ使用不可
StoreConnectionFailureDescription.message.Message.reason
ProductFetchFailed—.FailureReason、.FailedFetchProducts.Message
FailedOrder—.FailureReason、.Details—
PurchasesFetchFailureDescription.message、.failureReason.Message、.FailureReason—

検証

このパッケージを使用するコードを記述した後は、次の点を確認してください。

  1. プロジェクトがエラーなしでコンパイルされることを確認します。
  2. すべての API 呼び出しが api-notes.md の v5 シグネチャと一致することを確認します。v4 のレガシーパターン(IStoreListener、UnityPurchasing.Initialize、ConfigurationBuilder)は使用しないでください。
  3. api-notes.md の「Anti-Hallucination: Common v5 Mistakes」テーブルを確認します。OnStoreConnectionFailed は使用せず(OnStoreDisconnected を使用)、FetchProducts/FetchPurchases にコールバックを渡さず(イベントを使用)、product.receipt は使用せず(order.Info.Receipt を使用)にしてください。
  4. すべての必須イベントに Connect() の前にサブスクライブしていることを確認します(上記の「必須イベントのサブスクリプション」テーブルを参照)。
  5. 購入処理の 2 段階のフローを確認します。OnPurchasePending → コンテンツを付与 → ConfirmPurchase(pendingOrder)。
  6. すべての非同期処理について、成功イベントと失敗イベントの両方にサブスクライブしていることを確認します(OnProductsFetched/OnProductsFetchFailed、OnStoreConnected/OnStoreDisconnected など)。
  7. サブスクリプションを処理する場合、IsSubscribed() が bool にキャストされておらず、== Result.True と比較されていることを確認します。
  8. 同じプロジェクト内で更新済みファイルとレガシーバージョンが共存する場合は、CS0101/CS0111 のコンパイルエラーを避けるため、一意の名前空間(例:.Updated サフィックスを追加)を使用します。
  9. プロジェクトが OnAuthAccountChanged(v5.4 以降)にサブスクライブしている場合、ハンドラーが商品と購入を最初から再取得することを確認します。Unity IAP はこのイベントを発生させる前に両方のキャッシュをクリアします。ハンドラー内で GetProducts() や GetPurchases() を読み取らないでください。

コメント