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

Flutter测试卡In-App Purchase支付后5分钟收到取消退款通知

Flutter 内购测试支付后自动取消退款问题排查与修复

你遇到的这个问题是Google Play测试环境下的典型场景:未正确完成购买确认流程,导致Google在5分钟后自动取消测试订单并退款。Google规定非消耗型内购必须在购买完成后3天内调用completePurchase确认,测试环境下这个时限被缩短到5分钟,未确认的订单会被自动回收。

你的代码里的核心问题

  1. 提前触发成功逻辑:在purchaseFullVersion中,调用buyNonConsumable返回true就直接调用_handleSuccessfulPurchase,但这个返回值仅代表购买请求发起成功,不代表用户已经完成支付,此时PurchaseDetails还未进入purchased状态,后续的确认操作会无效。
  2. 重复确认逻辑:_handlePurchaseDetailsList和_handleSuccessfulPurchase中都调用了_acknowledgePurchase,容易导致状态冲突或重复操作。
  3. 状态处理不完整:没有处理PurchaseStatus.pending状态,部分测试卡支付会进入pending状态,需要等待状态更新后再处理确认。

修复步骤

1. 移除提前触发的成功逻辑

修改purchaseFullVersion方法,去掉buyNonConsumable后的_handleSuccessfulPurchase调用,仅提示购买已发起:

final bool purchaseResult = await _inAppPurchase.buyNonConsumable(purchaseParam: purchaseParam);
if (purchaseResult) {
  _updateNotice('购买已发起,请等待支付完成...');
  return true;
} else {
  _updateNotice('购买发起失败,请重试');
  return false;
}

2. 统一通过监听流处理所有购买状态

完善_handlePurchaseDetailsList,覆盖所有PurchaseStatus,并只对未确认的订单执行确认:

List<PurchaseDetails> _handlePurchaseDetailsList(List<PurchaseDetails> purchaseDetailsList) {
  for (PurchaseDetails purchaseDetails in purchaseDetailsList) {
    switch (purchaseDetails.status) {
      case PurchaseStatus.pending:
        _updateNotice('购买处理中,请稍候...');
        break;
      case PurchaseStatus.purchased:
        // 仅处理未确认的订单
        if (!purchaseDetails.pendingCompletePurchase) {
          _handleSuccessfulPurchase(purchaseDetails);
        }
        break;
      case PurchaseStatus.error:
        _handlePurchaseError(PlatformException(
          code: purchaseDetails.error?.code ?? 'unknown_error',
          message: purchaseDetails.error?.message ?? '购买出错',
        ));
        break;
      case PurchaseStatus.canceled:
        _updateNotice('购买已取消');
        break;
    }
  }
  _purchases.addAll(purchaseDetailsList);
  return _purchases;
}

3. 简化成功处理逻辑,直接传入PurchaseDetails

修改_handleSuccessfulPurchase,直接使用流中返回的PurchaseDetails,避免从列表中查找的错误:

void _handleSuccessfulPurchase(PurchaseDetails purchaseDetails) async {
  _updateNotice('购买成功!');
  homeProvider?.updatePurchaseStatus(true);
  String deviceId = await SharedPreferencesUtils.getStoredDeviceId();
  
  // 存储购买信息到Firestore
  await FirestoreService.storePurchaseInfo(deviceId, [purchaseDetails.productID]);
  
  // 确认购买
  await _acknowledgePurchase(purchaseDetails);
  
  // 移除已处理的订单
  _purchases.remove(purchaseDetails);
}

4. 确保确认逻辑的可靠性

检查_acknowledgePurchase,确保只在订单状态正确时调用:

void _acknowledgePurchase(PurchaseDetails purchaseDetails) async {
  try {
    if (purchaseDetails.status == PurchaseStatus.purchased && !purchaseDetails.pendingCompletePurchase) {
      await _inAppPurchase.completePurchase(purchaseDetails);
      _updateNotice('购买已确认');
    }
  } on PlatformException catch (e) {
    _handlePurchaseError(e);
  }
}

额外注意事项

  • 必须使用Google Play官方提供的测试卡,例如卡号4811 1111 1111 1111,有效期填未来日期(如12/30),CVV填任意3位数字。
  • 应用必须上传到Google Play控制台的测试渠道(内部/封闭/开放测试),且测试账号已添加到测试列表中。
  • 确认Google Play控制台内的内购商品状态为激活,未激活的商品无法完成正常购买流程。

内容的提问来源于stack exchange,提问作者M.Shaaban

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 06:09:53