You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS 16 下 StoreKit 功能异常:SKPaymentTransactionStatePurchased 回调未触发问题的解决方案咨询

iOS 16下StoreKit支付成功但updatedTransactions未收到Purchased回调的解决方案

我之前也踩过iOS 16上这个StoreKit的坑,支付流程走完了但代理方法死活不触发,确实让人头大。给你整理几个实战过的排查和解决方向,按优先级来试:

1. 先确认支付队列观察者的注册逻辑

这是最常见的问题根源:

  • 必须在App启动的最早期注册观察者,比如在application:didFinishLaunchingWithOptions:(传统AppDelegate)或者scene:willConnectToSession:options:(SceneDelegate)里就调用:
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    
    绝对不能等到发起支付前才临时注册,否则系统可能已经把交易状态推送了,你的观察者还没挂上。
  • 确保全程用同一个SKPaymentQueue实例(也就是defaultQueue),别自己创建新的队列对象,不然收不到回调。
  • 记得在合适的时机移除观察者(比如页面销毁时),但启动时的注册一定要优先执行。

2. 主动检查并处理队列中遗留的交易

iOS 16有时候会因为系统缓存或后台状态,导致交易状态没有主动推送给观察者。注册完观察者后,立刻手动遍历队列里的现有交易:

// 注册观察者后立即执行这段代码
for (SKPaymentTransaction *transaction in [SKPaymentQueue defaultQueue].transactions) {
    if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
        // 这里调用你的交易处理逻辑
        [self handlePurchasedTransaction:transaction];
        // 处理完一定要调用finishTransaction,避免重复触发
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
}

另外,所有交易处理完成后必须调用finishTransaction:,不然交易会一直留在队列里,导致后续回调逻辑混乱。

3. 排查沙箱和App Store Connect配置

  • 确认你的测试账号是有效的沙箱账号:iOS 16对沙箱的验证更严格,过期的账号、地区不匹配的账号都可能导致状态同步失败。可以去App Store Connect重新生成一个沙箱测试账号试试。
  • 检查内购项目的状态:确保内购产品已经在App Store Connect中配置完成,状态为“准备提交”或“已批准”,并且代码中使用的产品ID和后台的完全一致(大小写、拼写都不能错)。

4. 适配多Scene架构的问题

如果你的App采用了SceneDelegate架构:

  • 不要只在AppDelegate里注册观察者,因为iOS 16的多场景模式下,AppDelegate的启动方法可能不会覆盖所有场景,导致部分场景下观察者没注册上。
  • 建议用一个单例类来统一管理StoreKit的交易观察者,确保整个App生命周期内只有一个观察者实例被注册到队列中。

5. 系统层面的小技巧

  • 重启测试设备:有时候iOS的StoreKit服务会因为缓存或进程异常出现问题,重启设备能解决很多莫名其妙的回调丢失问题。
  • 检查网络:沙箱环境需要稳定的网络连接,支付过程中如果网络波动,可能导致交易状态无法同步到App。
  • 暂时关闭无关的权限请求:比如App Tracking Transparency弹窗,如果它阻塞了主线程,可能会影响代理方法的调用时机。测试时可以先注释掉相关代码,看是否恢复正常。

6. 考虑迁移到StoreKit 2(iOS 15+支持)

如果项目兼容iOS 15及以上,强烈建议迁移到StoreKit 2。它用异步回调代替了传统的代理模式,可靠性更高,能避免很多代理丢失的问题。示例代码(OC版本):

// 先获取对应的SKProduct,然后发起支付
[[SKPaymentQueue defaultQueue] purchaseProduct:targetProduct completionHandler:^(SKPaymentTransaction * _Nullable transaction, NSError * _Nullable error) {
    if (error) {
        // 处理支付错误
        NSLog(@"支付失败:%@", error.localizedDescription);
        return;
    }
    
    if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
        // 处理购买完成逻辑
        [self startDownloadForTransaction:transaction];
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
}];

先从第1、2点开始排查,这两个解决了大部分类似问题。如果还是不行,再依次检查后面的配置和系统问题。

内容的提问来源于stack exchange,提问作者neowinston

火山引擎 最新活动