implement-in-app-purchases について
Unity Purchasing パッケージでアプリ内購入を実装する Unity 向けスキルです。新規導入と移行を扱い、v5 のイベント駆動型接続と保留から確定までの購入フローを重視します。
主な機能
- 01プロジェクトを調査して実装経路を選択
- 02ストアへの接続と商品・購入情報の取得
- 03購入確定、復元、エンタイトルメント確認
- 04レシート検証とプラットフォーム固有の詳細
- 05他の購入システムからの移行手順
活用シーン
- 01購入機能のないプロジェクトへの Unity IAP 導入
- 02Unity IAP v4 またはネイティブ課金コードからの移行
- 03商品カタログ、サブスクリプション、購入復元の実装
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ unity-technologies/ skills --skill implement-in-app-purchasesインストール後、Claude Code で/implement-in-app-purchasesを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api-notes.mdcodeless-catalog.mdconvert-adapty.mdconvert-essentialkit.mdconvert-revenuecat.mdconvert-unipay.mdmigration-v4-to-v5.mdpath-add-iap-to-new-project.mdpath-convert-native-google-billing.mdpath-convert-native-storekit.mdpath-implement-iap-d2c.mdplatform-notes.mdpre-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 バージョンを確認し、適切な手順に振り分けます。振り分けが完了するまで、ほかのリファレンスファイルを読んだり、変更を加えたりしないでください。
詳細なリファレンス
- プロジェクトのスキャンと手順の振り分け(最初に読む): references/pre-check.md を参照してください
- API シグネチャとコード例: references/api-notes.md を参照してください
- プラットフォーム拡張(Apple、Google): references/platform-notes.md を参照してください
IAPProductCatalog.jsonの編集(スキーマ、小数のシリアル化、更新): references/codeless-catalog.md を参照してください- v4 から v5 への移行: references/migration-v4-to-v5.md を参照してください
- ネイティブの Google BillingClient を Unity IAP 5 に変換: references/path-convert-native-google-billing.md を参照してください
- ネイティブの iOS StoreKit プラグインを Unity IAP 5 に変換: references/path-convert-native-storekit.md を参照してください
- Essential Kit の課金機能を Unity IAP 5 に変換: references/convert-essentialkit.md を参照してください
- UniPay(FLOBUK)— 評価とガイダンス: references/convert-unipay.md を参照してください
- RevenueCat — 変換の評価とガイダンス: references/convert-revenuecat.md を参照してください
- Adapty — 変換の評価とガイダンス: references/convert-adapty.md を参照してください
- 既存の IAP がないプロジェクトに Unity IAP 5 を追加: references/path-add-iap-to-new-project.md を参照してください
- IAP D2C 機能を実装(サードパーティの決済プロバイダー — Stripe/Coda、v5.4 以降が必要): references/path-implement-iap-d2c.md を参照してください
リファレンスファイルは必要に応じてお読みください。具体的な API シグネチャ、プラットフォーム拡張の詳細、または移行の対応関係が必要な場合にのみ参照してください。
初期化フロー
UnityIAPServices.StoreController()を使ってStoreControllerを取得します(またはDefaultStore()、DefaultProduct()、DefaultPurchase()を使って個別のサービスを取得します)Connect()を呼び出す前に、必要なイベントをすべて登録します(下記の必須イベント登録を参照)await store.Connect()を呼び出して、プラットフォームストアに接続しますOnStoreConnectedで、store.FetchProducts(List<ProductDefinition>)を呼び出してカタログを読み込みます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 段階フローが必須です。
store.PurchaseProduct(product)— プラットフォームの購入ダイアログを開始しますOnPurchasePendingが発生します —PendingOrderを受け取ります- レシートを検証し、プレイヤーにコンテンツを付与します
store.ConfirmPurchase(pendingOrder)— トランザクションを確定します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 Play | CrossPlatformValidator と 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() | OnProductsFetched | OnProductsFetchFailed |
FetchPurchases() | OnPurchasesFetched | OnPurchasesFetchFailed |
Connect() | OnStoreConnected | OnStoreDisconnected |
PurchaseProduct() | OnPurchasePending | OnPurchaseFailed |
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 | — |
検証
このパッケージを使用するコードを記述した後は、次の点を確認してください。
- プロジェクトがエラーなしでコンパイルされることを確認します。
- すべての API 呼び出しが api-notes.md の v5 シグネチャと一致することを確認します。v4 のレガシーパターン(
IStoreListener、UnityPurchasing.Initialize、ConfigurationBuilder)は使用しないでください。 - api-notes.md の「Anti-Hallucination: Common v5 Mistakes」テーブルを確認します。
OnStoreConnectionFailedは使用せず(OnStoreDisconnectedを使用)、FetchProducts/FetchPurchasesにコールバックを渡さず(イベントを使用)、product.receiptは使用せず(order.Info.Receiptを使用)にしてください。 - すべての必須イベントに
Connect()の前にサブスクライブしていることを確認します(上記の「必須イベントのサブスクリプション」テーブルを参照)。 - 購入処理の 2 段階のフローを確認します。
OnPurchasePending→ コンテンツを付与 →ConfirmPurchase(pendingOrder)。 - すべての非同期処理について、成功イベントと失敗イベントの両方にサブスクライブしていることを確認します(
OnProductsFetched/OnProductsFetchFailed、OnStoreConnected/OnStoreDisconnectedなど)。 - サブスクリプションを処理する場合、
IsSubscribed()がboolにキャストされておらず、== Result.Trueと比較されていることを確認します。 - 同じプロジェクト内で更新済みファイルとレガシーバージョンが共存する場合は、CS0101/CS0111 のコンパイルエラーを避けるため、一意の名前空間(例:
.Updatedサフィックスを追加)を使用します。 - プロジェクトが
OnAuthAccountChanged(v5.4 以降)にサブスクライブしている場合、ハンドラーが商品と購入を最初から再取得することを確認します。Unity IAP はこのイベントを発生させる前に両方のキャッシュをクリアします。ハンドラー内でGetProducts()やGetPurchases()を読み取らないでください。