# 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_)에 전화할 때 스토어에서 이러한 구매를 정확하게 반환합니다.

## 구매 상태 확인

다음 두 가지 방법으로 구매 상태를 결정할 수 있습니다.

* [`Order`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.Orders.html)를 사용하여 `Order`가 `PendingOrder`, `ConfirmedOrder`, `DeferredOrder` 또는 `FailedOrder`인지 확인합니다.
* `CheckEntitlement`를 사용하여 `EntitledButNotFinished`, `EntitledUntilConsumed`, `FullyEntitled`, `NotEntitled` 또는 `Unknown`를 반환하는 [`EntitlementStatus`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.Entitlement.html#UnityEngine_Purchasing_Entitlement_Status)를 수신합니다.

### 구매 속성

| 속성              | 설명                            |
| --------------- | ----------------------------- |
| `transactionId` | 구매에 대한 고유 ID입니다.              |
| `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 순서)
{
    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 순서)
{
    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 앱 스토어 비슷한 보호 로직을 타임라인에 적용합니다.
> * 플레이어에게는 구매가 성공한 것으로 나타나고 사라지는 것으로, 구매가 끊어지는 것처럼 보입니다.

> **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는 처리된 것으로 확인될 때까지 기본 스토어에서의 거래를 계속 열립니다. 이렇게 하면 사용자가 소모품이 보류 중인 동안 애플리케이션을 다시 설치해도 소모품 구매가 손실되지 않습니다.
