# 初始化 Unity IAP

> 了解如何初始化 Unity IAP 包、配置基本设置以及验证设置以开始处理受支持平台上的应用内购。

使用 Unity 应用内购 (IAP) 之前，请[初始化 IAP 包](#initialize-in-app-purchasing)。

> **Important:**
>
> 如果要[集成直接到消费者 (D2C) 付款提供商](./payment-providers/workflow.md)，有一些差异，因此请改用[初始化服务以处理启动顺序](./payment-providers/initialize-services.md)。

如果要在项目中使用 [Unity Analytics](/analytics.md) 或 [Unity Authentication](/authentication.md)，必须先初始化 Unity Gaming Services (UGS)，然后再初始化 IAP。请参阅下面的 [Initialize Unity Gaming Services](#initialize-unity-gaming-services) 部分以了解操作方法。

## 初始化 Unity Gaming Services##initialize-unity-gaming-services

调用 `UnityServices.InitializeAsync()` 可初始化所有 Unity Gaming Services。此方法返回一个可用于跟踪初始化进度的`Task`。

要了解更多信息，请参阅[初始化示例](/services/services-core-api.md#initialization-example)。如需完整功能的示例，请导入 **06 Initialize Gaming Services** 示例（**Package Manager** > **In-App Purchasing** > **Samples**）。

如需了解更多信息，请参阅 [Services Core API](/services/services-core-api.md)。

## 初始化应用内购##initialize-in-app-purchasing

### 先决条件##prerequisites

完成 [Create a catalog in Editor](./create-catalog-in-editor.md)（为要购买的商品创建目录）中的步骤。

### 初始化步骤##initialization-steps

初始化包括以下步骤：

1. 获取应用商店的`StoreController`。
2. 将事件监听器附加到`StoreController`。
3. 连接到应用商店。
4. 从应用商店获取商品。
5. 从应用商店获取购买。

```cs
using System.Collections.Generic;
using UnityEngine.Purchasing;

public class MyIAPManager
{
    private StoreController m_StoreController;
    public MyIAPManager()
    {
        // Define products
        var catalogProvider = new CatalogProvider();
        catalogProvider.AddProduct("100_gold_coins", ProductType.Consumable,
            new StoreSpecificIds()
            {
                {"100_gold_coins_google", GooglePlay.Name},
                {"100_gold_coins_mac", MacAppStore.Name}
            });

        // Get StoreController
        m_StoreController = UnityIAPServices.StoreController();

        // Add event listeners
        m_StoreController.OnStoreDisconnected += OnStoreDisconnected;

        m_StoreController.OnProductsFetch += OnProductsFetch;
        m_StoreController.OnProductsFetchFailed += OnProductsFetchFailed;

        m_StoreController.OnPurchasesFetch += OnPurchasesFetch;
        m_StoreController.OnPurchasesFetchFailed += OnPurchasesFetchFailed;

        // Connect to store
        m_StoreController.Connect().ContinueWith(_ =>
        {
            // Fetch products from store
            catalogProvider.FetchProducts(
                list => m_StoreController.FetchProducts(list)
                
        });
    }

    /// <summary>
    /// Invoked when connection is lost to the current store, or on a Connect() failure.
    /// </summary>
    /// <param name="failure">Information regarding the failure.</param>
    private void OnStoreDisconnected(StoreConnectionFailureDescription failure)
    {
    }

    /// <summary>
    /// Invoked with products that are successfully fetched.
    /// </summary>
    /// <param name="products">Products successfully returned from the app store.</param>
    private void OnProductsFetch(List<Product> products)
    {
        // Fetch purchases for successfully retrieved products
        m_StoreController.FetchPurchases();
    }

    /// <summary>
    /// Invoked when an attempt to fetch products has failed or when a subset of products failed to be fetched.
    /// </summary>
    /// <param name="failure">Information regarding the failure.</param>
    private void OnProductsFetchFailed(ProductFetchFailed failure)
    {
    }

    /// <summary>
    /// Invoked when previous purchases are fetched.
    /// </summary>
    /// <param name="orders">All active pending, completed, and deferred orders for previously fetched products.</param>
    private void OnPurchasesFetch(Orders orders)
    {
    }

    /// <summary>
    /// Invoked when an attempt to fetch previous purchases has failed.
    /// </summary>
    /// <param name="failure">Information regarding the failure.</param>
    private void OnPurchasesFetchFailed(PurchasesFetchFailureDescription failure)
    {
    }

    /// <summary>
    /// Invoked when a purchase needs to be processed and fulfilled.
    /// </summary>
    /// <param name="order">The order awaiting fulfillment.</param>
    private void OnPurchasePending(PendingOrder order)
    {
    }
}
```

#### 获取 StoreController##get-a-storecontroller

`StoreController` 是与应用内购功能进行交互的主要接口。您可以通过调用 [UnityIAPServices.StoreController](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.UnityIAPServices.html#UnityEngine_Purchasing_UnityIAPServices_StoreController_System_String_) 来获取 `StoreController` 实例。如果提供了商店名称，它将返回默认商店控制器或请求的特定商店控制器。

#### 将事件处理程序附加到 StoreController##attach-event-handlers-to-the-storecontroller

要使应用商店正常运行，请将处理程序附加到这些事件：

* [OnStoreDisconnected](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_OnStoreDisconnected)
* [OnProductsFetch](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_OnProductsFetched)
* [OnProductsFetchFailed](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_OnProductsFetchFailed)
* [OnPurchasesFetched](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_OnPurchasesFetched)
* [OnPurchasesFetchFailed](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_OnPurchasesFetchFailed)
* [OnPurchasePending](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_OnPurchasePending)

将应用内购集成到项目中时，可能需要实现其他处理程序。有关通过 `StoreController` 提供的事件的完整列表，请参阅[事件](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#events)。

#### 连接到应用商店##connect-to-your-app-store

调用 [StoreController.Connect](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_Connect) 以连接到应用商店。返回的`Task`会在连接完成或失败时解析。连接失败将调用 `OnStoreDisconnected` 事件。在使用任何 IAP 功能之前，必须连接到商店。

#### 获取商品##fetch-products

> **Note:**
>
> 在获取商品之前定义商品。有关说明，请参阅[在 Editor 中创建目录](/iap/create-catalog-in-editor.md)。

要验证商品是否可供购买，请调用 [StoreController.FetchProducts](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_FetchProducts_System_Collections_Generic_List_UnityEngine_Purchasing_ProductDefinition__UnityEngine_Purchasing_IRetryPolicy_)。成功时，将调用 `OnProductsFetched` 事件以及成功返回的商品列表。如果失败，将调用 `OnProductsFetchFailed`。

只能为已成功退回的商品获取或发起购买。在运行时可以多次调用 `FetchProducts`，但必须等待以前的任何请求完成，然后才能再次调用 `FetchProducts`。

使用 Apple App Store 时，可能会在`FetchProducts`完成后为未处理的订单调用 `OnPurchasePending`。

##### GetProducts##getproducts

[`GetProducts`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_GetProducts) 和 `FetchProducts` 不可互换。确保在初始化期间调用 `FetchProducts`。每次调用时，`FetchProducts` 都会将结果商品附加到 `GetProducts` 返回的列表中。

#### 获取购买##fetch-purchases

调用 [`StoreController.FetchPurchases`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_FetchPurchases) 以请求玩家的当前有效订单。活跃订单包括`PendingOrders`、`ConfirmedOrders`（活跃订阅和活动非消耗品）和`DeferredOrders`。请参阅[购买](/iap/purchases.md)以了解更多信息。

对 `FetchPurchases` 的调用将触发以下两个事件处理程序之一：`OnPurchasesFetched`；将使用 `Orders` 对象调用该函数；该对象包含从商店或`OnPurchasesFetchFailed`返回的所有待处理订单、已确认订单和延迟订单；如果失败，将调用该函数。
使用 Google Play 时，这将对任何尚未处理的购买调用 `OnPurchasePending` 事件。

在开始使用应用内购功能时并非严格要求。但是，建议您在开始新购买之前获取和处理现有购买，否则可能会遇到意外行为。

请注意，如果在运行时获取其他商品，则需要再次获取购买。

##### 获取离线购买##fetch-purchases-offline

某些平台库（例如 Apple StoreKit 2）会在设备上缓存授权以便离线访问，而不会缓存商品数据。虽然不建议使用此方法，但仍可以在 `OnProductsFetchFailed` 回调后调用 `FetchPurchases`。在这种情况下，`FetchPurchases` 会返回购买信息，但关联商品将具有`type`[`ProductType.Unknown`](https://docs.unity3d.com/Packages/com.unity.purchasing@5.2/api/UnityEngine.Purchasing.ProductType.html)。此外，`ProductDefinition.id` 和 `ProductDefinition.storeSpecificId` 都设置为特定于商店的标识符。

> **Note:**
>
> 这不适用于 StoreKit 1。StoreKit 1 在设备上缓存收据时，包需要获取的商品数据才能解析收据数据。如果商品获取失败，`FetchPurchases` 不会返回任何购买信息。

##### GetPurchases##getpurchases

[`GetPurchases`](https://docs.unity3d.com/Packages/com.unity.purchasing@latest?subfolder=/api/UnityEngine.Purchasing.StoreController.html#UnityEngine_Purchasing_StoreController_GetPurchases) 和 `FetchPurchases` 不可互换。确保在初始化期间调用 `FetchPurchases`。与 `GetProducts` 和 `FetchProducts` 不同，`FetchPurchases` 不仅填充 `GetPurchases` 返回的列表，还会覆盖该列表。否则，资源包将根据事件的订单数据，尽可能保持与商店同步。

### 自动初始化 Codeless IAP##automatically-initialize-codeless-iap

有关如何设置 Codeless IAP 的说明，请参阅 [Set Up Codeless IAP](/iap/codeless-iap.md#set-up-codeless-iap)。

> **Note:**
>
> 如果也在脚本中手动初始化，则不应启用自动初始化，因为这可能会导致错误。

### Codeless IAP 的 Unity 游戏服务自动初始化##automatic-unity-game-services-initialization-for-codeless-iap

如果使用 Codeless IAP，请选中 **IAP Catalog** 窗口底部的 **Automatically initialize Unity Gaming Services** 复选框来启用 Unity Gaming Services 自动初始化。
这可确保 Unity Gaming Services 在应用程序启动时立即初始化。

要使用此功能，必须启用 **Automatic initialize UnityIAPServices（推荐）**。如果在 **IAP Catalog** 中没有看到这些复选框，可能是因为尚未在Catalog 窗口中添加商品。

这会使用默认初始化选项初始化 Unity Gaming Services。某些服务需要特定的初始化选项，可能无法与默认配置配合使用。如果需要自定义选项，请使用上述编码 API 初始化 Unity Gaming Services。
