Flutter中in_app_purchase包内购状态读取及退款状态获取咨询
关于Flutter in_app_purchase的两个问题解答
我来帮你一步步解决这两个问题,结合你的代码细节来说明:
1. 如何在Flutter中使用in_app_purchase包读取应用内购买状态
读取购买状态主要靠两个核心操作:监听实时购买更新流和查询历史购买记录,结合你的代码来优化:
(1)监听实时购买流
你代码里已经用到了purchaseUpdatedStream,但注意不要把订阅逻辑放在deliverProduct里——这个函数是用来交付商品的,应该在页面初始化时就启动监听,确保不会错过任何状态变化:
StreamSubscription<List<PurchaseDetails>>? _subscription; @override void initState() { super.initState(); _startPurchaseListener(); _checkPastPurchases(); // 初始化时同时查询历史 } void _startPurchaseListener() { _subscription = InAppPurchaseConnection.instance.purchaseUpdatedStream.listen( (List<PurchaseDetails> purchaseDetailsList) { _handlePurchaseUpdates(purchaseDetailsList); }, onDone: () => _subscription?.cancel(), onError: (error) { // 处理监听错误,比如网络问题 print('购买流监听错误: $error'); }, ); } void _handlePurchaseUpdates(List<PurchaseDetails> purchaseDetailsList) { for (var purchaseDetails in purchaseDetailsList) { switch (purchaseDetails.status) { case PurchaseStatus.pending: // 购买中,显示加载状态 setState(() => _purchasePending = true); break; case PurchaseStatus.purchased: // 购买成功,交付商品 deliverProduct(purchaseDetails); break; case PurchaseStatus.error: // 购买失败,提示用户 setState(() => _purchasePending = false); _showError(purchaseDetails.error!); break; case PurchaseStatus.canceled: // 用户取消购买 setState(() => _purchasePending = false); break; } } }
(2)查询历史购买记录
不管用户是首次打开APP还是重新进入,都需要主动查询历史购买来恢复状态,比如用户卸载重装后,或者退款后需要更新权限:
Future<void> _checkPastPurchases() async { final QueryPurchaseDetailsResponse response = await InAppPurchaseConnection.instance.queryPastPurchases(); if (response.error != null) { print('查询历史购买失败: ${response.error}'); return; } setState(() { // 过滤掉无效的购买(比如已退款、已撤销的) _purchases = response.pastPurchases.where((purchase) { // 核心判断:只有状态为已购买且未被撤销的才有效 return purchase.status == PurchaseStatus.purchased && !purchase.isRevoked; }).toList(); // 同步你的专业版状态 bool hasProAccess = _purchases.any((p) => p.productID == _kProId); if (!hasProAccess) { // 如果没有有效购买,移除专业版权限 _revokeProAccess(); } }); } void _revokeProAccess() { // 这里执行降级逻辑,比如清除本地存储的专业版标记 save_achat_deblocage(false); // 假设你的save_achat_deblocage支持传入状态 setState(() { // 更新UI状态 }); }
2. 处理退款后状态同步问题
你提到退款后插件无法获取信息,导致用户仍保留专业版——这是因为in_app_purchase的实时流不会主动推送退款通知,苹果/谷歌的退款事件需要主动查询或通过服务器端接收:
解决方案1:定期主动查询历史购买
在关键节点触发_checkPastPurchases函数,比如:
- APP启动时
- 用户进入付费功能页面时
- 后台切换回前台时
这样能及时发现已退款的购买,同步本地权限状态。
解决方案2:服务器端验证(推荐)
客户端查询可能有延迟,更可靠的方式是通过服务器接收官方通知:
- 苹果:配置App Store Server Notifications,当用户退款时,苹果会主动给你的服务器发送通知
- 谷歌:配置Real-Time Developer Notifications,同样会实时推送退款事件
服务器收到通知后更新用户状态,客户端每次打开APP或访问付费功能时,从服务器拉取最新权限状态,这样就能彻底解决退款不同步的问题。
针对你现有代码的修改建议
你的deliverProduct函数可以保留,但要确保它只负责交付有效购买,同时把订阅逻辑移到初始化阶段,并且添加定期查询的逻辑,避免退款后状态残留。
内容的提问来源于stack exchange,提问作者Nitneuq
相关产品推荐
相关产品推荐

