Flutter内购purchase stream购买成功后未触发问题排查
解决Flutter in_app_purchase购买成功但Stream未触发的问题
针对你遇到的支付成功后_onPurchaseUpdate从未被调用的问题,以下是几个排查方向和解决方案:
1. 补充历史购买恢复逻辑
测试环境或已完成的购买可能不会自动触发Stream事件,需要主动恢复购买记录来同步状态。在Purchases类初始化时添加恢复逻辑:
Purchases() { final purchaseUpdated = iapConnection.purchaseStream; _subscription = purchaseUpdated.listen( (List<PurchaseDetails> purchaseDetailsList) { _onPurchaseUpdate(purchaseDetailsList); }, onDone: _updateStreamOnDone, onError: _updateStreamOnError, ); // 初始化时恢复历史购买 _restorePurchases(); } Future<void> _restorePurchases() async { try { await iapConnection.restorePurchases(); } catch (e) { print('恢复购买失败: $e'); } }
2. 完善购买状态处理逻辑
你的_handlePurchase方法缺少对非成功状态的处理,且completePurchase的调用时机可能存在问题。调整为:
Future<void> _handlePurchase(PurchaseDetails purchaseDetails) async { switch (purchaseDetails.status) { case PurchaseStatus.purchased: if (purchaseDetails.productID == 'remove_ads') { // 执行移除广告逻辑,比如标记到本地存储 alreadyBoughtproductsList.add('remove_ads'); // 示例:SharedPreferences.getInstance().then((p) => p.setBool('no_ads', true)); } // 确保完成购买确认 if (purchaseDetails.pendingCompletePurchase) { await iapConnection.completePurchase(purchaseDetails); } break; case PurchaseStatus.error: print('购买错误: ${purchaseDetails.error?.message}'); break; case PurchaseStatus.pending: print('购买待处理,请等待支付完成'); break; default: break; } notifyListeners(); }
3. 验证Stream订阅的生命周期
确保Purchases实例在应用生命周期内唯一,未被意外销毁重建:
- 在
dispose方法中添加日志,确认是否被意外调用:@override void dispose() { print('Purchases实例被销毁'); _subscription.cancel(); super.dispose(); } - 检查
MultiProvider配置,确保Purchases始终是同一个实例(当前lazy: false配置是正确的,避免延迟初始化导致订阅丢失)。
4. 测试环境特殊配置检查
- 确认Google Play Console中已将测试账号添加到许可测试列表
- 内购商品已发布到测试轨道(至少是封闭测试)
- 测试应用的签名与上传到Play Console的签名一致(包括调试签名的配置)
5. 强制触发Stream事件
如果以上操作后仍未触发,可以在buy方法结束后手动调用恢复购买,强制同步状态:
Future<void> buy(ProductDetails productDetails) async { final purchaseParam = PurchaseParam(productDetails: productDetails); switch (productDetails.id) { case 'remove_ads': await iapConnection.buyNonConsumable(purchaseParam: purchaseParam); // 手动触发恢复,确保Stream收到事件 await _restorePurchases(); break; default: throw ArgumentError.value(productDetails, '${productDetails.id} 不是已知商品'); } }
内容的提问来源于stack exchange,提问作者xd0007
相关产品推荐
相关产品推荐

