You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter in_app_purchase在Apple沙箱环境中首次购买返回restored状态而非purchased

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 10:44:32