# IAP 버전 4에서 버전 5로 업그레이드

> 이 가이드를 따라 Unity 인앱 구매 버전 4에서 버전 5로 마이그레이션합니다.

인앱 구매(IAP) 버전 5(v5)는 연결 및 구매 흐름의 각 단계를 더 잘 제어할 수 있도록 아키텍처를 크게 개선했습니다. 마이그레이션을 수행하려면 기존 IAP 구현을 상당히 업데이트해야 하지만, 이 가이드에서는 전환에 도움이 되는 단계별 지침과 코드 샘플을 제공합니다.

> **Note:**
>
> SDK v5.4부터 Unity IAP는 [개발자 데이터 프레임워크](/cloud/developer-data.md.md)의 일부로 개발자 데이터를 처리합니다. 따라서 [Unity 동의](https://docs.unity3d.com/ScriptReference/UnityConsent.ConsentState.html) 모듈을 사용하여 [사용자 동의를 관리](/cloud/developer-data/user-consent.md.md)할 책임이 있습니다.

> **Note:**
>
> IAP 버전 5.3.0부터 IAP AI 기술에 액세스하여 프로젝트를 버전 4에서 버전 5로 마이그레이션할 수 있습니다.
>
> **프로젝트 설정** > **서비스** > **인앱 구매** 하단에서 다음 옵션 중 하나를 선택합니다.
>
> * **기술 폴더 열기**: 기술 파일이 포함된 폴더를 엽니다. 이 옵션을 사용하여 원하는 AI 툴에 IAP AI 기술을 복사하거나 설치합니다.
> * **클라우드 코드 설치**: 기술을 Claude Code에 직접 추가합니다. 이렇게 하면 `in-app-purchases`라는 기술이 설치됩니다.
>
> 기술을 설치한 후 AI 툴에서 `in-app-purchases`를 실행하고 프로젝트를 버전 4에서 버전 5로 마이그레이션하라는 메시지를 표시합니다.

## 변경 사항 개요##overview-of-changes

다음 표에는 IAP v5의 변경 사항과 구현 시 업데이트해야 하는 사항이 요약되어 있습니다. 업그레이드의 이점에 대한 자세한 내용은 [Unity 인앱 구매(IAP) v5.x](https://support.unity.com/hc/articles/47757890052372-Why-you-should-upgrade-to-Unity-In-App-Purchasing-IAP-v5-x) 지원 문서를 참고하십시오.

| 변경                                                                                                      | 필수 업데이트                                                                                                                |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| 초기화는 스토어 연결, 상품 페치, 구매 페치에 대한 별도의 비동기 호출로 분할됩니다.                                                        | [Replace UnityPurchasing.Initialize()](./upgrade-to-iap-v5.md#replace-unitypurchasing.initialize\(\))                  |
| `ConfigurationBuilder`가 제거됩니다. 이제 제품은 `CatalogProvider` 또는 `ProductDefinitions` 목록을 통해 정의됩니다.           | [ConfigurationBuilder 교체](./upgrade-to-iap-v5.md#replace-configurationbuilder)                                         |
| 스토어 확장 기능은 스토어 확장 서비스로 대체됩니다.                                                                           | [ConfigurationBuilder 교체](./upgrade-to-iap-v5.md#replace-configurationbuilder)                                         |
| `IDetailedStoreListener` 및 `IStoreListener`은 `StoreController` 및 개별 스토어 서비스에서 이벤트 핸들러(선택 사항)로 대체됩니다.    | [IDetailedStoreListener 및 IStoreListener 교체](./upgrade-to-iap-v5.md#replace-idetailedstorelistener-and-istorelistener) |
| `IStoreController`는 `UnityIAPServices.StoreController()`를 통해 언제든지 가져올 수 있는 `StoreController`로 대체됩니다.    | [IStoreController 교체](./upgrade-to-iap-v5.md#replace-istorecontroller)                                                 |
| `ProcessPurchase` 콜백은 새 구매에 대한 `OnPurchasePending`와 복원된 구매에 대한 `OnPurchasesFetched`로 대체됩니다.             | [구매 흐름 교체](./upgrade-to-iap-v5.md#replace-purchase-flow)                                                               |
| `RestoreTransactions`는 스토어 확장에서 `StoreController` 및 `PurchaseService`로 이동했습니다.                          | [복원 거래](./upgrade-to-iap-v5.md#restore-transactions)                                                                   |
| 자격 검사는 이제 `FetchPurchases` 또는 `CheckEntitlement`를 사용하여 이벤트에 기반합니다.                                      | [자격 검사 대체](./upgrade-to-iap-v5.md#replace-entitlement-checks)                                                          |
| Apple 앱 스토어 영수증 확인은 지원이 중단됩니다. Google Play 영수증 확인은 이제 `Order.Info.Receipt`를 사용합니다.                      | [영수증 확인 업데이트](./upgrade-to-iap-v5.md#receipt-validation)                                                               |
| `CodelessIAPStoreListener.initializationComplete` 를 `CodelessIAPStoreListener.IsInitialized()` 으로 대체한다. | [코드리스 IAP 업데이트](./upgrade-to-iap-v5.md#codeless-iap-specifics)                                                         |

## Replace UnityPurchasing.Initialize()##replace-unitypurchasing.initialize()

IAP v5부터 Unity IAP 패키지를 유연하게 초기화할 수 있습니다. 스토어에 연결하고 제품을 가져오고 구매를 독립적으로 비동기식으로 처리할 수 있습니다. 이 접근 방식은 성공적인 초기화를 차단할 수 있는 문제를 식별하고 해결하는 데 도움이 될 수 있습니다.

> **Note:**
>
> 버전 4 이하에서는 Unity IAP 패키지가 스토어에 연결되고 제품을 가져오고 패키지 초기화 시 구매를 동기식으로 가져옵니다. 패키지는 이러한 모든 단계를 완료한 후에만 성공적인 초기화를 리포트합니다.

다음 단계에 따라 `UnityPurchasing.Initialize()`의 동작을 대체합니다.

1. 전화 및 대기 `StoreController.Connect()`:
   * 이 호출이 완료되면 IAP가 현재 앱 스토어 연결됩니다.
2. 호출:
   * 제품을 `ConfigurationBuilder`에 추가하는 것과 마찬가지로 제품을 `CatalogProvider` 인스턴스에 추가할 수 있습니다. `ProductDefinitions` 목록을 `ProductService.FetchProducts()` 또는 `StoreController.FetchProducts()`에 전달할 수도 있습니다. 자세한 내용은 새 초기화 프로세스의 [코드 샘플을 참고하십시오](./upgrade-to-iap-v5.md#code-sample-of-new-initialization-process-using-storecontroller).
   * 요청이 성공적으로 완료되면 `OnProductsFetched` 이벤트 핸들러가 호출됩니다. 지정된 제품을 가져올 수 없으면 `OnProductsFetchFailed`가 호출됩니다.
3. 제품이 성공적으로 페치되면 `FetchPurchases()`를 호출합니다.
   * 요청이 성공적으로 완료되면 `OnPurchasesFetched` 이벤트 핸들러가 호출됩니다. `Orders` 객체는 앱 스토어에서 반환한 모든 디퍼드, 보류 중, 완료된 주문의 필터링 가능한 컬렉션을 포함합니다. 실패 시 `OnPurchasesFetchFailed`가 호출됩니다.

> **Note:**
>
> 기본적으로 호출 `FetchPurchases`는 세션에서 아직 처리되지 않은 보류 중인 구매에 대해 `OnPurchasePending`를 호출합니다. `StoreController.ProcessPendingOrdersOnPurchasesFetched(false)`를 사용하여 이 동작을 비활성화할 수 있습니다.

### StoreController를 사용한 새 초기화 프로세스의 코드 샘플##code-sample-of-new-initialization-process-using-storecontroller

다음 예시는 IAP v5를 초기화하는 방법을 보여 줍니다.

```cs
StoreController m_StoreController;  
  
async void InitializeIAP()  
{  
    m_StoreController = UnityIAPServices.StoreController();  
  
    m_StoreController.OnPurchasePending += OnPurchasePending;  
  
    await m_StoreController.Connect();  
  
    m_StoreController.OnProductsFetched += OnProductsFetched;
    m_StoreController.OnPurchasesFetched += OnPurchasesFetched;  
  
    var initialProductsToFetch = new List<ProductDefinition>  
    {  
        new(goldProductId, ProductType.Consumable),  
        new(diamondProductId, ProductType.Consumable)  
    };  
  
    m_StoreController.FetchProducts(initialProductsToFetch);  
}
void OnProductsFetched(List<Product> products)  
{  
    // Handle fetched products  
    m_StoreController.FetchPurchases();  
}  
void OnPurchasesFetched(Orders orders) {  
   // Process purchases, for example, check for entitlements from completed orders  
}
```

## IDetailedStoreListener와 IStoreListener 교체##replace-idetailedstorelistener-and-istorelistener

IAP v5에서는 구매 또는 초기화 처리를 위한 `IDetailedStoreListener` 또는 `IStoreListener` 구현이 더 이상 필요하지 않습니다. 이전에 `IDetailedStoreListener`에서 처리한 기능을 `StoreController` 또는 개별 `ProductService`, `PurchaseService` 및 `StoreService` 서비스에 이벤트 핸들러를 연결하여 교체합니다.

`StoreController`에 이벤트 핸들러를 추가하는 예제는 새 초기화 프로세스의 [코드 샘플을 참고하십시오](./upgrade-to-iap-v5.md#code-sample-of-new-initialization-process-using-storecontroller).

> **Note:**
>
> 언제든지 이벤트 핸들러를 추가하거나 제거할 수 있지만 특정 메서드를 호출하기 전에 특정 이벤트 핸들러를 사용할 것을 권장합니다. Unity IAP는 권장 이벤트 핸들러가 연결되기 전에 함수를 호출할 때 경고를 표시합니다.

마이그레이션하려면 각 `IDetailedStoreListener` 함수를 다음으로 대체합니다.

| 함수                                                                             | IAP v5 교체                                                                                                                                                                                                                                                                      |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `OnPurchaseFailed(Product, PurchaseFailureDescription)`                        | `StoreController.OnPurchaseFailed(FailedOrder)` 또는 `PurchaseService.OnPurchaseFailed(FailedOrder)`에 이벤트 핸들러 추가                                                                                                                                                                 |
| `OnInitialized(IStoreController controller, IExtensionProvider extensions)`    | `StoreController.Connect()` 또는 `StoreService.Connect()`가 완료된 후에도 실행을 계속합니다.                                                                                                                                                                                                    |
| `OnInitializeFailed(InitializationFailureReason error)`                        | `StoreService.OnStoreDisconnected(StoreConnectionFailureDescription)`, `ProductService.OnProductsFetchFailed(ProductFetchFailed)`, `PurchaseService.OnPurchasesFetchFailed(PurchasesFetchFailureDescription)`에 이벤트 핸들러를 추가합니다. `StoreController`를 통해 이러한 이벤트 핸들러를 추가할 수도 있습니다. |
| `OnInitializeFailed(InitializationFailureReason error, string message = null)` | `StoreController.OnStoreDisconnected(StoreConnectionFailureDescription)` 또는 `StoreService.OnStoreDisconnected(StoreConnectionFailureDescription)`에 이벤트 핸들러 추가                                                                                                                  |
| `PurchaseProcessingResult ProcessPurchase(PurchaseEventArgs args)`             | `StoreController.OnPurchasePending(PendingOrder)` 또는 `PurchaseService.OnPurchasePending(PendingOrder)`에 이벤트 핸들러 추가                                                                                                                                                             |

## ConfigurationBuilder 교체##replace-configurationbuilder

다음 `ConfigurationBuilder` 함수를 다음 동작으로 교체합니다.

| 함수                                  | IAP v5 교체                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ConfigurationBuilder.AddProduct()` | `ConfigurationBuilder.AddProduct()`를 호출하는 대신 `CatalogProvider.AddProduct()` 또는 `CatalogProvider.AddProducts()`를 통해 `CatalogProvider`의 인스턴스에 제품을 추가할 수 있습니다. 제품을 가져오려면 `CatalogProvider.FetchProducts`를 호출하고 `UnityIAPServices.DefaultProduct().FetchProductsWithNoRetries`와 같은 콜백을 전달하십시오. 제품 및 `CatalogProvider`에 대한 자세한 내용은 에디터에서 [카탈로그 만들기](./create-catalog-in-editor.md)를 참조하십시오. `ProductDefinitions`를 생성하고 `StoreController` 또는 `ProductService`에서 `FetchProducts()` 호출에 직접 전달할 수도 있습니다. |
| 4 및 5                               | 확장 스토어 서비스(예: `AppleStoreExtendedService`)에서 `IAppleConfiguration` 및 `IGoogleConfiguration`의 기능을 찾을 수 있습니다.                                                                                                                                                                                                                                                                                                                                                                                     |

> **Note:**
>
> 지원되지 않는 플랫폼(예: 에디터 또는 Android에서 `AppleStoreExtendedService` 가져오기)에서 스토어 확장 서비스를 가져오는 경우 서비스가 null이 됩니다. 이벤트 핸들러를 추가하거나 설정을 변경하기 전에 서비스가 null이 아닌지 항상 확인하십시오.

## IStoreController 교체##replace-istorecontroller

`IStoreController`를 `StoreController`로 교체합니다. `StoreController`는 `IStoreListener`와 유사한 IAP 기능을 노출하지만, 언제든지 `UnityIAPServices.StoreController()`를 호출하여 `StoreController`를 가져올 수 있습니다.

`IStoreController`의 이러한 방법을 `StoreController`의 다음 방법으로 대체합니다.

| IStoreController          | StoreController                 | 참고 사항                                                                                  |
| ------------------------- | ------------------------------- | -------------------------------------------------------------------------------------- |
| `products`                | `GetProducts`                   | `GetProducts`는 제품 목록을 반환합니다.                                                           |
| `InitiatePurchase`        | `Purchase` 또는 `PurchaseProduct` | `Purchase` 함수에는 더 이상 `payload` 인수가 없습니다. Google Billing v3에서 개발자 페이로드에 대한 지원이 중단되었습니다. |
| `FetchAdditionalProducts` | `FetchProducts`                 | `FetchProducts` 는 초기 제품을 가져오는 데에도 사용됩니다.                                               |
| `ConfirmPendingPurchase`  | `ConfirmPurchase`               | `ConfirmPurchase`에는 `PendingOrder`가 필요해                                                |

## 구매 플로 교체##replace-purchase-flow

구매를 시작하려면 `Purchase()` 또는 `PurchaseProduct()`on `StoreController` 또는 `PurchaseService`에 전화하십시오. 보류 중인 구매를 확인하려면 확인하려는 `PendingOrder`가 있는 `StoreController.ConfirmPurchase(PendingOrder)` 또는 `PurchaseService.ConfirmPurchase(PendingOrder)`에 문의하십시오. 구매 흐름에 대한 자세한 내용은 [구매](./purchases.md)를 참고하십시오.

IAP v4 이하에서 `ProcessPurchase` 메서드는 모든 구매 이벤트를 자동으로 처리했습니다. IAP v5에서 구매 핸들링은 다음 콜백을 사용합니다.

* `OnPurchasePending`: 새 구매가 호출되었습니다.
* `OnPurchasesFetched`: 복원된 구매에 대해 호출됩니다.

이러한 두 새로운 콜백 내에서 기존의 `ProcessPurchase` 로직을 사용합니다.

## 거래 복원##restore-transactions

`RestoreTransactions`는 스토어 확장에서 `StoreController` 및 `PurchaseService`로 이동했습니다.

확인된 구매는 `FetchPurchases()` 또는 `CheckEntitlement()` 호출을 통해 자동으로 복원됩니다.

## 자격 검사 교체##replace-entitlement-checks

제품에 대한 사용자의 권한을 확인하기 위해 IAP는 이벤트에 의존합니다. `FetchPurchases`를 호출하고 `OnPurchasesFetched` 이벤트를 처리하여 가져온 모든 제품의 자격을 확인할 수 있습니다. 단일 제품의 자격을 확인하려면 `CheckEntitlement`에 전화하여 `OnCheckEntitlement` 이벤트를 처리하십시오.

## 추가 상품 페치##fetch-additional-products

추가 제품 목록과 함께 `StoreController` 또는 `ProductService`에서 `FetchProducts`을 호출하여 `OnPurchasesFetched` 이벤트 핸들러를 트리거합니다. 또는 `CatalogProvider` 인스턴스에서 `FetchProducts`를 호출할 수도 있습니다. `ProductService`를 통해 상품을 가져오는 예제는 새 초기화 프로세스의 [코드 샘플을 참고하십시오](./upgrade-to-iap-v5.md#code-sample-of-new-initialization-process-using-storecontroller). `CatalogProvider`에서 `FetchProducts` 호출 예제는 [에디터에서 카탈로그 만들기](./create-catalog-in-editor.md)를 참조하십시오.

## 영수증 확인##receipt-validation

Apple 앱 스토어 영수증 확인은 지원이 중단되었습니다. 영수증 확인은 Google Play 스토어에서만 지원됩니다. 영수증을 가져오려면 `Product.Receipt` 대신 `Order`에서 `Order.Info.Receipt`를 사용하십시오.

> **Note:**
>
> 가능한 한 빨리 StoreKit 1 영수증에서 [StoreKit 2 jwsRepresentation](https://developer.apple.com/documentation/storekit/verificationresult/jwsrepresentation-21vgo)으로 전환하여 신뢰성, 보안, 성능을 향상시키고 최종적으로 사용자에게 더 나은 경험을 제공합니다.

> **Note:**
>
> 서버 측 확인을 위해 [OrderInfo.Apple.jwsRepresentation](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.IAppleOrderInfo.html#UnityEngine_Purchasing_IAppleOrderInfo_jwsRepresentation)을 사용합니다.

## 코드리스 IAP 세부 사항##codeless-iap-specifics

다음의 `CodelessIAPStoreListener` 함수를 다음과 같이 대체합니다.

| `CodelessIAPStoreListener`함수                      | IAP v5 교체                                  |
| ------------------------------------------------- | ------------------------------------------ |
| `CodelessIAPStoreListener.initializationComplete` | `CodelessIAPStoreListener.IsInitialized()` |
