# 購入 /Purchases

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

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