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

Flutter in_app_purchase:恢复待处理购买权限异常问题排查

问题核心结论

这是代码逻辑的问题,恢复购买在支付待处理时,平台会返回对应的待处理状态,你的代码没有正确处理恢复后的购买状态,直接默认所有恢复的购买都是已完成状态,才导致提前授予权限。

代码中的关键问题
  1. 恢复购买的状态判断缺失:你的HandlePurchases函数中,只要是PurchaseStatus.restored就直接调用PurchasePremium授予权限,但恢复的购买也可能处于pending(待处理)状态,你没有在恢复分支里校验这个核心状态。
  2. 本地存储逻辑过于绝对:一旦授予权限就直接把premium设为true并永久存储,没有后续的状态回收逻辑,导致即使后续支付被取消或失败,用户依然能保留权限。
修复方案

1. 修正购买状态处理逻辑

统一处理所有购买(新购+恢复)的状态,只有当购买明确处于purchased完成状态时,才授予高级权限。修改HandlePurchases函数:

void HandlePurchases(List<PurchaseDetails> purchaseDetailsList){
  purchaseDetailsList.forEach((PurchaseDetails purchaseDetails) async {
    switch(purchaseDetails.status) {
      case PurchaseStatus.error:
        PopUp("Error with Purchase");
        _revokePremiumIfNeeded();
        break;
      case PurchaseStatus.pending:
        PopUp("Purchase is Pending");
        _revokePremiumIfNeeded();
        break;
      case PurchaseStatus.purchased:
        PurchasePremium(true);
        if (purchaseDetails.pendingCompletePurchase) {
          await _iap.completePurchase(purchaseDetails);
        }
        break;
      case PurchaseStatus.restored:
        // 恢复时必须检查购买的实际完成状态,而不是直接恢复权限
        if (purchaseDetails.purchaseState == PurchaseState.purchased) {
          PurchasePremium(false);
          if (purchaseDetails.pendingCompletePurchase) {
            await _iap.completePurchase(purchaseDetails);
          }
        } else {
          // 恢复的购买仍待处理,收回权限
          _revokePremiumIfNeeded();
          PopUp("Restored purchase is still pending");
        }
        break;
      case PurchaseStatus.canceled:
        PopUp("Purchase was Cancelled");
        _revokePremiumIfNeeded();
        break;
    }
  });
}

// 新增辅助函数:收回高级权限
void _revokePremiumIfNeeded() {
  if (hasPremium) {
    setState(() {
      hasPremium = false;
      prefs?.put('premium', false);
    });
    if (contextReference != null) {
      ScaffoldMessenger.of(contextReference!).showSnackBar(
        SnackBar(content: Text("Premium access revoked due to incomplete payment")),
      );
    }
  }
}

2. 优化本地存储与权限校验

  • 不要把premium布尔值作为唯一权限判断依据,建议存储购买的凭证信息(比如purchaseDetails.verificationData),每次启动应用(在线时)重新校验凭证的有效性。
  • 给本地缓存添加有效期:比如本地存储的权限状态最多保留24小时,超过时间后,必须在线拉取最新购买状态才能继续使用高级功能。

3. 解决离线与滥用问题

  • 离线场景:离线时允许使用缓存的权限,但进入高级功能时提示用户“当前离线,权限基于上次验证结果”,并在联网后自动重新校验。
  • 慢处理拒付卡滥用:
    • 每次启动应用(在线状态)强制拉取_getPastPurchases(),用最新的购买状态覆盖本地缓存。
    • 若没有后端,可在客户端记录用户的购买历史,若短时间内出现多次“待处理-取消”的循环,临时限制该用户恢复购买的频率。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 01:52:52