Flutter in_app_purchase在Apple沙箱环境中首次购买返回restored状态而非purchased
我之前测试in_app_purchase沙箱支付时也踩过这个坑,当时看到返回restored状态整个人都懵了——明明是全新沙箱用户第一次购买啊!后来折腾了半天,总结出几个可能的原因和解决思路:
先排查代码里的误操作
先检查下你的初始化流程,是不是在APP启动或者购买流程开始前,不小心调用了restorePurchases()?有些开发者会把恢复购买的逻辑放在启动时同步用户已购项目,但如果测试设备缓存了之前的沙箱交易记录,可能导致新用户的购买被误判为恢复。另外要确认购买流严格走buyNonConsumable()或buySubscription(),没有混入恢复逻辑。沙箱环境的“缓存幽灵”在搞鬼
Apple的沙箱测试环境本身就有不少玄学问题,其中之一就是交易记录的缓存混乱。如果你在同一个设备上用其他沙箱用户测试过相同产品ID,哪怕切换了新沙箱用户,设备上的沙箱缓存可能还没清空,导致新购买被识别为“恢复”。这种情况在生产环境几乎不会发生,因为生产环境的交易记录完全和用户Apple ID绑定,不会有沙箱的缓存混乱问题。怎么确认是不是沙箱的锅
你可以在代码里打印交易关键字段验证:void handlePurchaseUpdate(List<PurchaseDetails> purchases) { for (var purchase in purchases) { if (purchase.status == PurchaseStatus.restored || purchase.status == PurchaseStatus.purchased) { print('产品ID: ${purchase.productID}'); print('交易时间: ${purchase.transactionDate}'); print('原始交易时间: ${purchase.originalTransactionDate}'); } } }如果是沙箱缓存问题,
transactionDate和originalTransactionDate会完全一致——本质还是首次购买,只是沙箱给了错误状态;如果是真恢复(比如用户之前购买过换设备恢复),originalTransactionDate会比transactionDate早很多。业务逻辑上兼容两种状态
其实从业务角度,purchased和restored的最终结果都是用户获得产品权限,所以你可以在代码里把这两种状态都视为“已完成购买”,只要验证交易的产品ID正确、签名有效就行。不用纠结沙箱里的状态异常,重点保证生产环境逻辑没问题。
内容来源于stack exchange

