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

疑难解答

本页介绍开发者在集成 AppCoins iOS SDK(Swift 与 Unity)时最常遇到的问题及其解决方法。每个条目均采用相同结构:现象、原因和解决方法。


isAvailable() 始终返回 false

现象: 即使在真机上,AppcSDK.isAvailable()(Swift)或 AppCoinsIAP.ConfigureStoreAsync 中的 Automatic 模式判定(Unity)也始终不会启用 AppCoins 计费。

原因:

  1. 测试环境未配置——应用未被识别为通过替代应用市场分发。
  2. 设备运行的 iOS 版本低于 17.4。
  3. 应用是从 Apple App Store 或 TestFlight 安装的。

完整的安装来源列表及其对可用性的影响,请参见运行时检测的原理

解决方法:

  1. 在 Xcode 中打开目标的 Build Settings 并搜索 Marketplaces。在 Deployment 下将值设置为 com.aptoide.ios.store
  2. 在您的 scheme 中进入 Run → Options,在 Distribution 下拉框中选择 com.aptoide.ios.store
  3. 在运行 iOS 17.4 及以上版本的真机上运行。

或者,您也可以无需重新构建,在设备上打开 Safari 并访问以下地址来在运行时强制启用 AppCoins 模式:

{bundle_id}.iap://wallet.appcoins.io/default/mode?value=appcoins

请将 {bundle_id} 替换为您应用的 bundle identifier。使用 value=apple 可测试 Apple 计费回落,使用 value=automatic 可恢复正常检测。请注意,为防止滥用,模式覆盖对从 Apple App Store 安装的构建无效。


购买时出现 notEntitled 错误

现象: 调用 product.purchase()(Swift)或 controller.InitiatePurchase(Unity)后,未显示支付页面就立即抛出或返回 AppCoinsSDKError.notEntitled

原因:

  • 尚未为该 target 添加 Keychain Sharing 能力。
  • 钥匙串分组设置为了错误的值(Xcode 有时会自动填入团队标识符或 bundle identifier)。

解决方法:

  1. 在 Xcode 中选择您的 target,打开 Signing & Capabilities 标签页。
  2. 点击 + 并添加 Keychain Sharing 能力。
  3. Keychain Groups 列表中删除所有已有条目,并准确输入 com.aptoide.appcoins-wallet
  4. 执行 Clean 后重新构建。
⚠️
Keychain Sharing 分组必须准确设置为 com.aptoide.appcoins-wallet——不能有前缀、后缀或 bundle ID。任何其他值都会在运行时导致 notEntitled

商品数组为空 / 出现 productUnavailable 错误

现象: Product.products(for:)(Swift)返回空数组,或 GetProducts(Unity)触发 OnProductsFetchFailed;也可能是 product.purchase() 抛出 productUnavailable

原因:

  1. 应用尚未在 Aptoide Connect 中提交并通过审核。
  2. 代码中的 SKU 标识符与 Aptoide Connect 中定义的不完全一致(标识符区分大小写)。

解决方法:

  1. 打开 Aptoide Connect,确认应用条目已存在且已通过审核。
  2. 在应用条目中进入 Products,逐字符核对每个 SKU 标识符是否与您传入 Product.products(for:)(Swift)或 Unity ProductCatalog 的值完全一致。
  3. 只有在审核通过之后,商品才可被查询。
⚠️
只有在应用于 Aptoide Connect 上通过审核之后,才能查询应用内商品。

支付跳转未完成(购买一直挂起)

现象: 用户被跳转到支付方式页面,但应用始终未收到购买结果,购买一直处于待处理状态。

原因(Swift):

  1. 未在 URL context 处理方法中调用 AppcSDK.handle(redirectURL:)
  2. Info → URL Types 中缺少角色为 Editor 的 URL scheme $(PRODUCT_BUNDLE_IDENTIFIER).iap

解决方法:

  1. 在 Xcode 中打开目标的 Info 标签页。在 URL Types 下确认存在如下条目:
    • URL Schemes: $(PRODUCT_BUNDLE_IDENTIFIER).iap
    • Role: Editor
  2. SceneDelegate.swift 中确认 scene(_:openURLContexts:) 调用了 AppcSDK.handle(redirectURL:)。注意:AppcSDK.initialize() 必须在应用启动时于 willConnectTo 中调用,而不能放在 URL 处理方法内:
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if AppcSDK.handle(redirectURL: URLContexts.first?.url) { return }
// your existing URL handling
}

对于 Unity,后处理构建脚本会自动添加该 URL scheme。如果购买仍然挂起,请从 Unity 重新构建 Xcode 工程,并确认 URL Type 已出现在 Xcode target 的 Info 标签页中。


应用崩溃或重启后用户丢失了购买

现象: 用户已付款,但由于应用在购买流程中崩溃或被强制退出而未收到商品;重新启动后商品仍然缺失。

原因: 应用未在启动时遍历 Transaction.unfinished(Swift)或调用 FetchPurchases(Unity),因而没有恢复已付款但未消耗的交易。

解决方法(Swift):

在应用的初始化流程中、isAvailable() 检查之后,加入未完成交易的处理:

func processUnfinishedTransactions() async {
guard await AppcSDK.isAvailable() else { return }

for await verificationResult in Transaction.unfinished {
switch verificationResult {
case .verified(let transaction):
giveItemToUser(productID: transaction.productID)
await transaction.finish()
case .unverified(_, let error):
print("Unverified unfinished transaction: \(error.description)")
}
}
}

解决方法(Unity):

Connect() 之前设置 ProcessPendingOrdersOnPurchasesFetched(true),随后调用 FetchPurchases()。未完成的购买会通过 OnPurchasePending 重新到达——与新购买使用同一个处理方法。

async void Start()
{
await AppCoinsIAP.ConfigureStoreAsync(AppCoinsStoreMode.Automatic);

controller = UnityIAPServices.StoreController();
controller.OnPurchasePending += OnPurchasePending;

// Must be set before Connect so FetchPurchases results come through OnPurchasePending
controller.ProcessPendingOrdersOnPurchasesFetched(true);

await controller.Connect();
controller.FetchPurchases(); // recovers unfinished transactions
}
⚠️
未完成的交易将在 24 小时后自动退款。请在每次应用启动时恢复这些交易,确保用户收到其已付款的商品。

transaction.id 类型不匹配(Swift)

现象: 在比较或存储 transaction.id 时出现编译错误或非预期行为——在 StoreKit 下可用的代码在 AppCoins SDK 下无法编译或产生错误结果。

原因: StoreKit 的 Transaction.idUInt64,而 AppCoins SDK 的 Transaction.idString。从 StoreKit 集成中直接复制的代码会失效。

解决方法:

将所有比较和存储逻辑更新为将 transaction.id 视为 String

// Wrong (StoreKit pattern)
let id: UInt64 = transaction.id

// Correct (AppCoins SDK)
let id: String = transaction.id

如果您在同一代码库中同时对接 StoreKit 和 AppCoins 计费,请在需要时转换 StoreKit 的交易 ID:

let appCoinsCompatibleID = String(storeKitTransaction.id)

Unity:调用 Connect 之前未 await ConfigureStoreAsync

现象: Unity IAP 已连接,但使用了错误的计费提供方,或 OnProductsFetched 从不触发。即使在本应启用的设备上,AppCoins 计费也未生效。

原因:ConfigureStoreAsync 完成之前就调用了 controller.Connect()。Unity IAP 初始化时,AppCoins 的商店提供方尚未注册。

解决方法:

在调用 Connect 之前,务必 await ConfigureStoreAsync

async void Start()
{
var selectedStore = await AppCoinsIAP.ConfigureStoreAsync(AppCoinsStoreMode.Automatic);
Debug.Log("Selected store: " + selectedStore);
await controller.Connect();
}
⚠️
必须在调用 Connect 之前 await ConfigureStoreAsync。否则,AppCoins 商店可能来不及注册,Unity IAP 会回落到 Apple 或静默失败。

Unity:设备上 AppCoins 未启用(Automatic 模式)

现象: 在 iOS 17.4 及以上版本的真机上使用 Automatic 模式,但 AppCoinsIAP.SelectedStore 始终为 "AppleAppStore"

原因: 缺少测试环境配置——与 Swift 中 isAvailable() 返回 false 的根本原因相同。

解决方法:

应用相同的 Xcode 与 scheme 设置:

  1. Build Settings 中将 Marketplaces 设置为 com.aptoide.ios.store
  2. 在 scheme 的 Run → Options → Distribution 中选择 com.aptoide.ios.store

或在设备上通过 Safari 使用深度链接强制启用 AppCoins 模式:

{bundle_id}.iap://wallet.appcoins.io/default/mode?value=appcoins