メインコンテンツまでスキップ

在 Unity IAP v5 基础上接入 AppCoins

本指南介绍如何为已使用 Unity IAP v5(5.0 或更高版本)的 Unity 游戏接入 AppCoins Billing。如果您的工程使用的是更早的 Unity IAP 版本,请先参见在 Unity IAP v4 或更早版本基础上接入 AppCoins。您只需在现有的 Connect() 调用之前多加一行代码。您已编写的所有事件处理方法、商品定义和确认逻辑均保持不变——在通过 Aptoide 分发的构建中,AppCoins 会成为当前生效的商店。

配置

GitHub releases 页面 下载最新的 .unitypackage 并导入:

  1. 在 Unity 中依次选择 Assets → Import Package → Custom Package...
  2. 选择已下载的 .unitypackage 文件。
  3. Import Unity Package 对话框中确认所有项目均已选中,然后点击 Import

插件文件将出现在 Assets/Plugins/iOS/AppCoinsSDKPlugin/ 下。

概览

AppCoins 以自定义商店提供方的形式与 Unity IAP v5 集成。配置完成后,您已在使用的 StoreController API 会在条件满足时自动将购买路由至 AppCoins Billing,其他情况下则回落到 Apple Billing。无需使用另一套购买 API。

唯一的改动

在任何使用 AppCoins API 的文件中只需添加两样东西:命名空间导入,以及 Connect() 之前的一次 await

变更前:

_controller = UnityIAPServices.StoreController();
_controller.OnProductsFetched += OnProductsFetched;
_controller.OnPurchasePending += OnPurchasePending;
_controller.ProcessPendingOrdersOnPurchasesFetched(true);
await _controller.Connect();
_controller.FetchProducts(new List<ProductDefinition> { new ProductDefinition("your_product_id", ProductType.Consumable) });
_controller.FetchPurchases();

变更后:

using AppCoins.Unity; // Add this using directive

// ↓ This is the only new line required
await AppCoinsIAP.ConfigureStoreAsync(AppCoinsStoreMode.Automatic);

_controller = UnityIAPServices.StoreController();
_controller.OnProductsFetched += OnProductsFetched;
_controller.OnPurchasePending += OnPurchasePending;
_controller.ProcessPendingOrdersOnPurchasesFetched(true);
await _controller.Connect();
_controller.FetchProducts(new List<ProductDefinition> { new ProductDefinition("your_product_id", ProductType.Consumable) });
_controller.FetchPurchases();
⚠️
警告: 请在 controller.Connect() 之前调用并 await ConfigureStoreAsync。未先配置商店就调用 Connect() 会导致商店提供方错误或缺失。

Automatic 模式的作用

AppCoinsStoreMode.Automatic 会在启动时查询 AppDistributor.current,并在 iOS 17.4 及以上、且安装来源不是 Apple App Store 或 TestFlight 时启用 AppCoins Billing。按安装来源的完整说明请参见运行时检测的原理

无论当前生效的是哪个商店,您的 OnPurchasePendingOnProductsFetchedOnPurchaseConfirmedOnPurchaseFailed 处理方法都会以完全相同的方式触发。在 ConfigureStoreAsync 返回后检查 AppCoinsIAP.SelectedStore,即可知道走的是哪条路径:

var selectedStore = await AppCoinsIAP.ConfigureStoreAsync(AppCoinsStoreMode.Automatic);
// selectedStore is either "AppCoinsAppStore" or "AppleAppStore"
Debug.Log("Active billing store: " + selectedStore);

收据的变化

如果您执行服务端购买验证,请注意:当 AppCoins Billing 生效时,order.Info.Receipt 中包含的是 AppCoins 的 JSON 负载,而非 Apple 收据。收据结构和服务端验证流程请参见购买验证

变更前后的完整示例

下面的示例展示了完整的 Unity IAP v5 配置,并突出显示了接入 AppCoins 所需的唯一改动。

变更前 —— 仅 Apple 的标准 Unity IAP v5:

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Extension;

public class IAPManager : MonoBehaviour
{
private StoreController _controller;

private async void Start()
{
_controller = UnityIAPServices.StoreController();
_controller.OnProductsFetched += OnProductsFetched;
_controller.OnPurchasePending += OnPurchasePending;

_controller.ProcessPendingOrdersOnPurchasesFetched(true);

await _controller.Connect();

_controller.FetchProducts(new List<ProductDefinition> { new ProductDefinition("your_product_id", ProductType.Consumable) });
_controller.FetchPurchases();
}

private void OnProductsFetched(List<Product> products)
{
foreach (var product in products)
{
Debug.Log($"Product: {product.definition.id}{product.metadata.localizedPriceString}");
}
}

public void BuyProduct(string productId)
{
_controller.PurchaseProduct(productId);
}

private void OnPurchasePending(PendingOrder order)
{
var product = order.CartOrdered.Items().FirstOrDefault()?.Product;
if (product == null) return;

GiveItemToUser(product.definition.id);
_controller.ConfirmPurchase(order);
}

private void GiveItemToUser(string productId)
{
Debug.Log($"Delivering item: {productId}");
}
}

变更后 —— 接入 AppCoins 后的同一份代码(高亮行为新增):

using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Purchasing;
using UnityEngine.Purchasing.Extension;
using AppCoins.Unity; // Add this using directive

public class IAPManager : MonoBehaviour
{
private StoreController _controller;

private async void Start()
{
// ↓ This is the only new line required
await AppCoinsIAP.ConfigureStoreAsync(AppCoinsStoreMode.Automatic);

_controller = UnityIAPServices.StoreController();
_controller.OnProductsFetched += OnProductsFetched;
_controller.OnPurchasePending += OnPurchasePending;

// Re-fire OnPurchasePending for any unfinished purchases found by FetchPurchases()
_controller.ProcessPendingOrdersOnPurchasesFetched(true);

await _controller.Connect();

_controller.FetchProducts(new List<ProductDefinition> { new ProductDefinition("your_product_id", ProductType.Consumable) });

// Trigger recovery of unfinished purchases — results arrive via OnPurchasePending
_controller.FetchPurchases();
}

private void OnProductsFetched(List<Product> products)
{
foreach (var product in products)
{
Debug.Log($"Product: {product.definition.id}{product.metadata.localizedPriceString}");
}
}

public void BuyProduct(string productId)
{
_controller.PurchaseProduct(productId);
}

private void OnPurchasePending(PendingOrder order)
{
var product = order.CartOrdered.Items().FirstOrDefault()?.Product;
if (product == null) return;

GiveItemToUser(product.definition.id);
_controller.ConfirmPurchase(order);
}

private void GiveItemToUser(string productId)
{
Debug.Log($"Delivering item: {productId}");
}
}

AppCoins 专属的新增内容只有 using AppCoins.Unity; 指令和 await AppCoinsIAP.ConfigureStoreAsync(AppCoinsStoreMode.Automatic); 调用。其余部分——ProcessPendingOrdersOnPurchasesFetched(true)FetchProducts(List<ProductDefinition>)FetchPurchases()——都是标准的 Unity IAP v5 用法,在变更前和变更后的版本中都应存在。