# SDK を通じた購入の履行

> プレイヤーが購入した製品の購入情報を取得し、購入状態を判別します。

> **Important:**
>
> 支払いプロバイダーの場合は、`UnityIAPServices`または`StoreController`を呼び出すときにストア名 (`PaymentProvider.Name`) を指定する必要があります。`PaymentProvider.Name` は、D2C (ダイレクトツーコンシューマー) プロバイダーインテグレーションを使用することを指定し、プロバイダーのディスプレイ名を返しません。

Unity Iap はストアから購入情報を取得するため、アプリケーションはプレイヤーが購入したものを認識し、処理できます。これにより、ユーザーがアプリケーション外や別のデバイスでアイテムを購入した場合でも、購入履歴に基づいてゲームからユーザーにコンテンツやエンタイトルメントを配信できます。

購入は[`Order`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.Order.html)オブジェクトとして表されます。`Order`には、購入に関連するすべての詳細が含まれ、ストアで追跡および管理するために必要な情報を提供します。

## 購入の取得

ユーザーによる購入はストアから取得できます。ただし、消費型製品は、消費後にアプリケーションによって追跡される必要があります。これは、すでに満たされた消耗品はストアから返却されないためです。非消費型製品およびサブスクリプションの場合、ストアは[`FetchPurchases`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.IPurchaseService.html#UnityEngine_Purchasing_IPurchaseService_FetchPurchases)または[`CheckEntitlement`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.IPurchaseService.html#UnityEngine_Purchasing_IPurchaseService_CheckEntitlement_UnityEngine_Purchasing_Product_)の呼び出し時にこれらの購入アイテムを正確に返します。

## 購入状態の確認

購入の状態は、次の 2 つの方法で確認できます。

* [`Order`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.Orders.html) を使用して、`Order`が `PendingOrder`、`ConfirmedOrder`、`DeferredOrder`、`FailedOrder` のいずれであるかを判別します。
* [`EntitlementStatus` を](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.Entitlement.html#UnityEngine_Purchasing_Entitlement_Status)受け取るには `CheckEntitlement` を使用します。`EntitledButNotFinished`、`EntitledUntilConsumed`、`FullyEntitled`、`NotEntitled`、または `Unknown` を返します。

### 購入属性

| 属性              | 説明                      |
| --------------- | ----------------------- |
| `transactionId` | 購入の一意の識別子。              |
| `product`       | 購入したプロダクト               |
| `quantity`      | 購入した製品の数量。              |
| `receipt`       | ストアでの購入を検証するためのレシートデータ。 |

### 購入の状態

| State       | 説明                       |
| ----------- | ------------------------ |
| `Pending`   | 購入は支払われましたが、まだ履行されていません。 |
| `Confirmed` | 購入が完了し、承認されました。          |
| `Failed`    | エラーにより購入が失敗しました。         |
| `Deferred`  | 購入は支払いを待っています。           |

## 購入の処理

[`OnPurchasePending`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.IPurchaseService.html#UnityEngine_Purchasing_IPurchaseService_OnPurchasePending) コールバックは、購入が行われ、履行を待っているときに実行されます。アプリケーションはこの時点で購入を完了する必要があります。例えば、ローカルコンテンツのロックを解除したり、購入レシートをサーバーに送信してサーバー側のゲームモデルを更新します。

`OnPurchasePending`は、初期化が成功した後、任意の時点で呼び出される可能性があることに注意してください。`OnPurchasePending` ハンドラーの実行中にアプリケーションがクラッシュした場合は、次に Unity Iap が初期化されるときに再度実行されます。独自の重複除外ロジックの実装を検討してください。

> **Note:**
>
> 購入を確認しないと、ストアから購入が返送されます。ユーザーを保護するために、一部のストアでは自動的に返金される場合もあります。

```cs
// Handle restore on initialization
private async void Start()
{
    // Setup, e.g. add listeners to your StoreController...
    m_StoreController.OnPurchasePending += OnPurchasePending;
    m_StoreController.OnPurchasesFetched += OnPurchasesFetched;
    await m_StoreController.Connect();

    // Fetch previous purchases (includes confirmed orders)
    m_StoreController.FetchPurchases();
}

// Handle new purchases and pending transactions
private void OnPurchasePending(PendingOrder order)
{
    ProcessPurchase(order);
}

// Handle fetched purchases (includes previously confirmed orders)
private void OnPurchasesFetched(オーダーオーダー)
{
    Foreach (var confirmedOrder in orders.ConfirmedOrders)
    {
        if (confirmedOrder.CartOrdered.Items().FirstOrDefault()?.Product.definition.type != ProductType.Consumable)
        {
            // Mark non-consumable and subscription products as entitled on fetch, as they only need to be granted once
            MarkAsEntitled(confirmedOrder.CartOrdered.Items().FirstOrDefault().Product);
        }
    }
}

// Your ProcessPurchase logic
private void ProcessPurchase(PendingOrder order)
{
    Foreach (var product in order.CartOrdered.Items())
    {
        // Grant product
        GrantProduct(product);
    }
    // Confirm the order to finalize the transaction
    m_StoreController.ConfirmPurchase(order);
}
```

## 購入確認と信頼性

Unity Iap では、ネットワークの停止やアプリケーションのクラッシュが発生した場合でも確実に購入が履行されるように、購入を明示的に確認する必要があります。課金は行われたが履行されなかった場合、Unity Iap は次回の初期化時にアプリケーションに課金を配信します。このプロセスにより、購入フローが中断されたとき、またはアプリケーションがオフラインの間に購入が完了したときに、購入が失われるのを防ぎます。

購入を正常に完了したら、関連する`PendingOrder`で[`ConfirmPurchase`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.IPurchaseService.html#UnityEngine_Purchasing_IPurchaseService_ConfirmPurchase_UnityEngine_Purchasing_PendingOrder_)を呼び出し、ストアに購入の承認を求めます。

> **Warning:**
>
> 購入を常に承認します。そうしないと、以下の問題が発生する可能性があります。
>
> * Unity Iap は、承認するまで、後続の`FetchPurchases`呼び出しまたはセッション開始ごとに注文の`OnPurchasePending`を再実行します。独自の重複除外ロジックを使用しない場合は、同じ項目を複数回許可できます。
> * 一部のストアでは、購入が自動的に逆になります。例えば、google playは3日後に未承認の購入を返金し、Apple App Storeはより厳しくないTimelineに同様の保護ロジックを適用します。
> * プレイヤーにとっては、購入が成功したように見えてから消えるため、壊れた購入のように見えます。

> **Note:**
>
> 消耗品の場合、購入を承認すると、ストアは再度返品しません。常に消費型型ゲーム内報酬をリモートで維持します。消費型型ゲーム内報酬をローカルに保存すると、データを復元する手段がなく、データを失うリスクがあります。

## 購入がクラウドに永続化されたことを確認する

消費型購入をクラウドに保存する場合は、購入が正常に維持されたときに[`ConfirmPurchase`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.IPurchaseService.html#UnityEngine_Purchasing_IPurchaseService_ConfirmPurchase_UnityEngine_Purchasing_PendingOrder_)を呼び出す必要があります。

`Pending`を返す場合、Unity Iap は処理完了が確認されるまで、基礎となるストアでトランザクションを開いたままにします。これにより、消費型の保留中にユーザーがアプリケーションを再インストールした場合でも、消費型購入が失われなくなります。

## 購入の復元##restore-purchases

ユーザーがアプリケーションを再インストールしたりデバイスを切り替えたりしたときに、以前に所有していた製品やサブスクリプションへのアクセスを回復できるようにします。IAP がエンタイトルメントのレコードを取得し、アクセスを付与する方法を理解します。

* ユーザーがアプリケーションを再インストールすると、Unity Iap は最初の`StoreController.FetchPurchases()`呼び出し時に所有する製品を復元します。
* IAP は、すべての購入（すべての状態）を含む `Orders` オブジェクトで `OnPurchasesFetched` リスナーを起動します。
* `PurchaseService.ProcessPendingOrdersOnPurchasesFetched` 設定が `true` に設定されている場合、IAP は満たされない購入ごとに `OnPurchasePending` リスナーを呼び出します。
* 同じセッションでの後続の`FetchPurchases()`呼び出しは、同じセッションですでに確認済みの注文の`OnPurchasePending`をトリガーしません。

## SDK でのサーバーサイド検証の使用##use-server-side-validation-alongside-the-sdk

Unity IAP(アプリケーション内課金)SDKの使用中にバックエンドAPIを呼び出すことができます。このハイブリッド アプローチでは、プレイヤーに報酬を与える前に、Unityの記録に対してトランザクションを直接検証することで、サーバーが権限の役割を果たすことができます。標準のバックエンド API メソッドとは異なり、これはウェブフックのパブリックエンドポイントを公開する必要がないため、攻撃対象領域を減らし、サーバーインフラストラクチャを簡素化できます。

### クライアントサイドの実装##client-side-implementation

購入が開始されると、SDK は `PendingOrder` オブジェクトを返します。`OrderInfo.TransactionId`を抽出し、バックエンドに渡します。

### バックエンド認証##backend-authentication

> **Important:**
>
> Unity Iap API を呼び出すには、バックエンドが [サービスアカウント](/cloud/accounts/create-service-account.md) として認証される必要があります。

サービスアカウントのキー ID と秘密鍵を使用して、トークン交換を実行し、ステートレス Bearer トークンを受け取ります。詳細については、「 ステートレストークンを使用した [API の認証](https://services.docs.unity.com/docs/service-account-auth/#authenticate-an-api-using-a-stateless-token)方法 」を参照してください。

以下のトークン交換エンドポイントを参照してください。

```http
POST https://services.api.unity.com/auth/v1/token-exchange?projectId={projectId}&environmentId={envId}
```

### 注文の検証##validate-the-order

バックエンドが Bearer トークンを取得したら、以下のリクエストで Unity Iap Order サービスをクエリします。

```http
GET https://iap.services.api.unity.com/v1/projects/{projectId}/environments/{envId}/orders/{orderId}
```

この`orderId`は、前のステップの`TransactionId`と同じです。
以下の重要な反応フィールドを参照してください。

* アイテムを許可する前に、`status` は `paid` である必要があります。
* `paymentProviderResourceId` には、基礎となるストライプチェックアウトセッション ID が含まれます (ストライプダッシュボードで相互リファレンスが必要な場合)。

### 注文の履行と完了##fulfill-and-complete-the-order

以下のワークフローを参照して、サーバー権限で注文を完了します。

1. 状態が有料であることと、productSKUが予期される項目と一致することを確認します。
2. プレイヤーのデータベースを新しいエンタイトルメントで更新。
3. バックエンドが成功コードをクライアントに返したら、以下のいずれかの方法を使用して Unity Iap システムでトランザクションを完了します。
   * [APIによる注文の直接更新](https://staging.docs.unity.com/en-us/iap/payment-providers/implement-backend.md#update-an-order)
   * クライアント呼び出しを`m_StoreController.ConfirmPurchase(order)`します。

詳細については、[API で注文](./implement-backend.md#mark-orders-as-fulfilled-via-api)を履行済みとしてマークする方法に関するセクションを参照してください。

## 次のステップ##next-steps

このページは、IAPによるD2C(ダイレクト ツー コンシューマー)支払いプロバイダーを設定するワークフローの一部です。このワークフローを続行するには、以下のオプションのいずれかを選択します。

[Integrate D2C payment providers](./workflow.md#fulfill-purchases-through-the-sdk): Integrate D2C payment provider with IAP ワークフロー (D2C 支払いプロバイダーと IAP ワークフローの統合) ページに戻ります。
[Test Stripe](./test-stripe.md): ワークフローの次のステップに進み、D2C支払いプロバイダーを設定します。
