使用flutter_inapp_purchase校验订阅有效性时chcekSubscribed报错
报错核心原因
调用checkSubscribed出现类型转换错误,基本是三个问题导致:
- 方法名拼写错误:代码中写的
chcekSubscribed字母顺序错误,Dart找不到对应方法时会返回动态类型的null,后续操作很容易触发类型转换异常。 - 传参类型不匹配:该方法要求入参为字符串类型的订阅商品ID,很多开发者误传入
PurchasedItem实例、动态类型的Map结构值,触发强类型校验报错。 - 版本兼容问题:
flutter_inapp_purchase5.0及以上版本调整了方法返回值类型,旧版本中直接将返回值强转为bool的写法不再适用,新版本返回值为Future<PurchasedResult?>类型,直接强转布尔值必然报错。
正确的订阅有效性校验实现
前置准备
首先在pubspec.yaml中锁定稳定版本依赖,避免dev版本的API变动问题:
dependencies: flutter_inapp_purchase: ^5.3.1
初始化阶段必须先完成商店连接,再拉取订阅商品信息,确保本地配置和商店后台配置一致:
// 初始化内购连接 await FlutterInappPurchase.instance.initialize(); // 配置你在商店后台上架的所有订阅商品ID const List<String> kSubscriptionIds = ['pro_monthly', 'pro_yearly']; // 拉取订阅商品信息,校验ID有效性 await FlutterInappPurchase.instance.getSubscriptions(kSubscriptionIds);
修复调用逻辑,规避类型错误
以下是会触发报错的典型错误写法,直接替换即可:
// 错误写法:拼写错误、传参错误、非法强转 bool isSubscribed = await FlutterInappPurchase.instance.chcekSubscribed(purchasedItem) as bool;
正确的校验逻辑,包含类型安全处理和兜底校验:
Future<bool> verifySubscriptionValid() async { bool validStatus = false; try { // 注意方法名拼写,传入字符串类型的商品ID final PurchasedResult? checkResult = await FlutterInappPurchase.instance.checkSubscribed( kSubscriptionIds.first, ); // 先判空再判断状态,禁止直接强转bool if (checkResult != null && checkResult.status == PurchaseStatus.purchased) { // 拉取本地有效购买记录做二次校验,避免checkSubscribed跨平台返回异常 final List<PurchasedItem>? availablePurchases = await FlutterInappPurchase.instance.getAvailablePurchases(); if (availablePurchases != null) { validStatus = availablePurchases.any((item) { // 校验商品ID匹配 if (!kSubscriptionIds.contains(item.productId)) return false; // 安卓端校验:未确认的订阅会在15天后自动退款,不算有效订阅 if (Platform.isAndroid && (item.isAcknowledgedAndroid == false)) return false; // 校验交易时间在订阅周期内,按自己的订阅时长调整判断逻辑 if (item.transactionDate == null) return false; final transactionTime = DateTime.fromMillisecondsSinceEpoch(int.parse(item.transactionDate!)); return transactionTime.isAfter(DateTime.now().subtract(const Duration(days: 31))); }); } } } catch (e) { // 异常兜底:直接拉取可用购买记录判断,避免接口报错导致校验失败 final fallbackPurchases = await FlutterInappPurchase.instance.getAvailablePurchases(); validStatus = fallbackPurchases?.any((p) => kSubscriptionIds.contains(p.productId)) ?? false; } return validStatus; }
跨平台注意事项
- 安卓端:本地校验仅做前端状态判断,正式环境建议搭配服务端校验Google Play返回的
purchaseToken,避免本地伪造订阅状态。 - iOS端:用户重装应用、跨设备登录时,需要先调用
FlutterInappPurchase.instance.refreshReceipt()刷新本地收据,再执行校验逻辑,否则会返回错误的未订阅状态。 - 调用时机:必须等内购初始化完成、和商店连接成功后再调用校验方法,初始化未完成时方法会返回动态类型null,触发类型转换错误。
类型错误快速排查清单
- 核对方法名拼写,确认是
checkSubscribed,无字母顺序错误 - 核对入参类型:第一个参数必须是
String类型的商品ID,禁止传入对象、Map等其他类型值 - 核对返回值接收类型:使用
PurchasedResult?接收返回值,禁止直接用bool类型接收并强转 - 核对空安全处理:所有可空返回值必须做判空后再取属性,避免空值触发类型转换异常
内容的提问来源于stack exchange,提问作者Kajitharaj Suthakaran
相关产品推荐
相关产品推荐

