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

Flutter中如何检查Play Store订阅续订及处理多购买记录?

Flutter in_app_purchase订阅续订失效与状态检查解决方案

一、获取并筛选最新订阅记录

Play Store会为每次续订生成新的购买记录,必须从历史记录中筛选出最新的有效订阅,这是解决续订失效的核心。

实现步骤:

  1. 调用InAppPurchase.instance.queryPastPurchases()获取所有历史购买记录;
  2. 过滤出订阅类型且状态为已购买/已恢复的记录;
  3. 按到期日期(优先)或购买日期排序,取最新的一条。

代码示例:

Future<PurchaseDetails?> getLatestActiveSubscription() async {
  final response = await InAppPurchase.instance.queryPastPurchases();
  if (response.error != null) {
    // 处理查询错误(如网络问题)
    return null;
  }

  // 筛选目标订阅的有效记录
  final activeSubs = response.pastPurchases.where((purchase) {
    return purchase.productID == "你的订阅商品ID" // 替换为实际商品ID
        && purchase.purchaseType == PurchaseType.subscription
        && (purchase.status == PurchaseStatus.purchased || purchase.status == PurchaseStatus.restored);
  }).toList();

  if (activeSubs.isEmpty) return null;

  // 按到期日期倒序,取最晚到期的订阅
  activeSubs.sort((a, b) {
    final aExpiry = a.subscriptionPurchaseDetails?.expiryDate ?? a.purchaseDate!;
    final bExpiry = b.subscriptionPurchaseDetails?.expiryDate ?? b.purchaseDate!;
    return bExpiry.compareTo(aExpiry);
  });

  return activeSubs.first;
}

二、检查订阅状态与过期日期

拿到最新订阅记录后,通过subscriptionPurchaseDetails字段获取订阅的核心信息:

关键字段说明:

  • autoRenewing:是否开启自动续订;
  • expiryDate:订阅到期时间;
  • purchaseDate:购买/续订时间(兜底用)。

状态检查代码:

Future<bool> isSubscriptionActive() async {
  final latestSub = await getLatestActiveSubscription();
  if (latestSub == null) return false;

  final expiryDate = latestSub.subscriptionPurchaseDetails?.expiryDate;
  if (expiryDate != null) {
    // 直接用到期日期判断是否活跃
    return expiryDate.isAfter(DateTime.now());
  }

  // 极端情况(如无到期日期),用购买日期加套餐天数兜底
  final purchaseDate = latestSub.purchaseDate!;
  return purchaseDate.add(const Duration(days: 30)).isAfter(DateTime.now()); // 替换为你的套餐天数
}

三、修复续订失效问题

之前只依赖首次购买的purchaseDate计算有效期,忽略了续订后的新记录和到期日期,调整逻辑如下:

1. 监听所有购买状态更新

通过purchaseStream监听包括续订在内的所有购买事件,触发有效期更新:

StreamSubscription<List<PurchaseDetails>>? _purchaseStreamSub;

void initPurchaseListener() {
  _purchaseStreamSub = InAppPurchase.instance.purchaseStream.listen(
    (purchaseList) => _handlePurchaseUpdates(purchaseList),
    onError: (err) => print("购买流错误: $err"),
    onDone: () => _purchaseStreamSub?.cancel(),
  );
}

void _handlePurchaseUpdates(List<PurchaseDetails> purchaseList) {
  for (final purchase in purchaseList) {
    if (purchase.status == PurchaseStatus.purchased || purchase.status == PurchaseStatus.restored) {
      // 无论首次购买还是续订,都重新同步最新订阅状态
      _updateUserSubscriptionValidity();
    }
  }
}

Future<void> _updateUserSubscriptionValidity() async {
  final latestSub = await getLatestActiveSubscription();
  if (latestSub == null) {
    // 无活跃订阅,重置本地有效期记录
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove("subscription_expiry");
    return;
  }

  // 将最新到期日期保存到本地,方便快速判断
  final expiryDate = latestSub.subscriptionPurchaseDetails?.expiryDate;
  if (expiryDate != null) {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString("subscription_expiry", expiryDate.toIso8601String());
  }
}

2. 应用启动时同步状态

每次启动应用都调用_updateUserSubscriptionValidity(),避免应用关闭期间续订导致状态不一致。

新手注意事项

  • 确保Play Console中订阅商品已开启自动续订;
  • 不要仅依赖本地保存的到期日期,定期调用queryPastPurchases()同步最新状态;
  • 处理用户取消订阅的情况:autoRenewing变为false时,到期后订阅失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:42:09