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

Flutter中in_app_purchase无法检测订阅续订问题求助

问题根源分析

  1. transactionDate字段不适合判断续订:Google Play订阅中,transactionDate通常对应初始购买的日期,而非每次续订的交易日期。即使续订成功,该字段也不会更新,导致你无法通过它检测到续订行为。
  2. restorePurchases()的局限性:该方法仅返回历史购买记录的快照,不会主动推送实时续订事件;且插件可能将同一订阅的多次续订合并为一条记录,无法直接区分。
  3. purchaseStream触发限制:订阅续订发生时,若应用处于后台或未运行状态,Google Play不会主动通过purchaseStream推送事件,导致应用无法实时感知。

解决方案

1. 改用订阅到期时间判断续订

每次续订都会延长订阅的到期时间,这是检测续订最可靠的依据。需要从订阅的服务器验证数据中解析出到期时间,替代transactionDate。

修改_listenToPurchaseUpdated方法:

Future<void> _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) async {
  for (final PurchaseDetails purchaseDetails in purchaseDetailsList) {
    if (purchaseDetails.status == PurchaseStatus.purchased || purchaseDetails.status == PurchaseStatus.restored) {
      if (!mounted) return;

      // 解析Google Play服务器验证数据(JSON格式)
      final Map<String, dynamic> verificationData = jsonDecode(purchaseDetails.verificationData.serverVerificationData);
      final List<dynamic> receiptInfos = verificationData['latest_receipt_info'];
      final Map<String, dynamic> latestReceipt = receiptInfos.last;
      final String expiryDateStr = latestReceipt['expiry_date'];
      final int expiryTimestamp = int.parse(expiryDateStr);
      final DateTime currentExpiryDate = DateTime.fromMillisecondsSinceEpoch(expiryTimestamp);

      // 获取Firestore存储的最后到期时间戳
      final String lastExpiryTimestamp = await SubscriptionService().getLastExpiryTimestamp();
      
      if (lastExpiryTimestamp.isEmpty) {
        // 首次订阅,直接更新
        await deliverProduct(purchaseDetails);
        await SubscriptionService().updateLastExpiryTimestamp(expiryDateStr);
      } else {
        final DateTime lastExpiryDate = DateTime.fromMillisecondsSinceEpoch(int.parse(lastExpiryTimestamp));
        if (currentExpiryDate.isAfter(lastExpiryDate)) {
          // 到期时间延长,判定为续订成功
          loggy.info("订阅已续订,更新用户权限");
          await deliverProduct(purchaseDetails);
          await SubscriptionService().updateLastExpiryTimestamp(expiryDateStr);
        }
      }
    }

    // 完成购买流程
    if (purchaseDetails.pendingCompletePurchase) {
      await _inAppPurchase.completePurchase(purchaseDetails);
    }
  }
}

2. 主动定期查询订阅状态

由于purchaseStream无法保证实时接收续订事件,建议监听应用生命周期,在应用回到前台时主动查询订阅状态:

class YourScreen extends StatefulWidget {
  @override
  _YourScreenState createState() => _YourScreenState();
}

class _YourScreenState extends State<YourScreen> with WidgetsBindingObserver {
  late StreamSubscription<List<PurchaseDetails>> _subscription;
  final InAppPurchase _inAppPurchase = InAppPurchase.instance;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _setupPurchaseStream();
    _inAppPurchase.restorePurchases();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    _subscription.cancel();
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    // 应用从后台回到前台时,主动查询订阅状态
    if (state == AppLifecycleState.resumed) {
      _inAppPurchase.restorePurchases();
    }
  }

  void _setupPurchaseStream() {
    final Stream<List<PurchaseDetails>> purchaseUpdated = _inAppPurchase.purchaseStream;
    _subscription = purchaseUpdated.listen(
      _listenToPurchaseUpdated,
      onDone: () => _subscription.cancel(),
      onError: (error) => loggy.error("购买流错误: $error"),
    );
  }

  // 你的_listenToPurchaseUpdated方法...
}

3. 配置实时订阅通知(可选但推荐)

为实现真正的实时检测,可配置Google Play实时开发者通知,通过Firebase Cloud Messaging(FCM)接收订阅状态变更推送:

  • 在Google Play控制台开启实时开发者通知,配置FCM服务器密钥。
  • 应用中集成FCM,监听SUBSCRIPTION_RENEWED等订阅事件。
  • 收到通知后,调用restorePurchases()或直接查询订阅状态,更新用户权限。

4. 修复代码细节问题

  • 方法名拼写错误:hendleError → handleError。
  • 为purchaseDetailsList指定类型List<PurchaseDetails>,避免类型不安全。

测试注意事项

  • Google Play测试订阅的最短续订周期为5分钟(测试模式),需等待足够时间观察效果。
  • 确保测试账号已添加到Google Play控制台的许可测试列表中。

内容的提问来源于stack exchange,提问作者mr.Penguin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 04:39:34