如何将VerifyReceipt API支付状态映射到PurchaseStatus以调用completePurchase
问题解析
使用in_app_purchase包验证购买流程时,遇到以下核心问题:
- 调用
buyNonConsumable完成购买后,服务器验证收据返回payment_state:1(已支付)和acknowledgement_state:0(未确认),此时purchaseDetails.pendingCompletePurchase为true,需执行completePurchase但因应用意外关闭未执行。 - 后续从服务器恢复购买数据时,缺少
PurchaseStatus枚举值的官方映射规则,手动映射触发Android端断言错误:'package:in_app_purchase_android/src/in_app_purchase_android_platform.dart': Failed assertion: line 176 pos 7: 'purchase is GooglePlayPurchaseDetails': On Android, the purchase should always be of type GooglePlayPurchaseDetails.
Google Play & App Store 收据状态 ↔ PurchaseStatus 映射
Google Play
基于收据中的acknowledgement_state和payment_state字段映射:
acknowledgement_state:0+payment_state:1→PurchaseStatus.purchased(pendingCompletePurchase=true,需调用completePurchase)acknowledgement_state:1+payment_state:1→PurchaseStatus.purchased(pendingCompletePurchase=false,无需操作)payment_state:0→PurchaseStatus.pending(支付中)或PurchaseStatus.error(支付失败),需结合订单上下文判断
App Store
基于交易状态字段映射:
- 已支付但未执行
finishTransaction→PurchaseStatus.purchased(pendingCompletePurchase=true) - 已支付且完成
finishTransaction→PurchaseStatus.purchased(pendingCompletePurchase=false) - 支付中 →
PurchaseStatus.pending - 支付失败 →
PurchaseStatus.error
解决方案
1. 优先使用插件原生接口恢复购买状态
不要手动构造PurchaseDetails实例,直接调用插件的历史购买查询接口获取平台原生实例,彻底避免类型不匹配问题:
final queryResponse = await InAppPurchase.instance.queryPastPurchases(); for (final purchase in queryResponse.pastPurchases) { if (purchase.pendingCompletePurchase) { await InAppPurchase.instance.completePurchase(purchase); } }
说明:Android端的GooglePlayPurchaseDetails和iOS端的AppStorePurchaseDetails由插件原生层生成,包含平台特定的订单元数据,能通过断言检查。
2. 服务器同步状态时的平台专属构造
若必须从服务器同步订单状态,需根据平台类型构造对应子类:
Android 示例
import 'package:in_app_purchase_android/in_app_purchase_android.dart'; if (Platform.isAndroid) { final androidPurchase = GooglePlayPurchaseDetails( productID: 'your_product_id', purchaseID: 'server_purchase_id', verificationData: PurchaseVerificationData( localVerificationData: 'local_receipt', serverVerificationData: 'server_returned_receipt', source: IAPSource.googlePlay, ), status: PurchaseStatus.purchased, pendingCompletePurchase: true, ); await InAppPurchase.instance.completePurchase(androidPurchase); }
iOS 示例
import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart'; if (Platform.isIOS) { final iosPurchase = AppStorePurchaseDetails( productID: 'your_product_id', purchaseID: 'server_purchase_id', verificationData: PurchaseVerificationData( localVerificationData: 'local_receipt', serverVerificationData: 'server_returned_receipt', source: IAPSource.appStore, ), status: PurchaseStatus.purchased, pendingCompletePurchase: true, ); await InAppPurchase.instance.completePurchase(iosPurchase); }
3. 增加类型检查兜底
调用completePurchase前先做类型校验,避免断言错误:
if (purchase is GooglePlayPurchaseDetails || purchase is AppStorePurchaseDetails) { await InAppPurchase.instance.completePurchase(purchase); }
4. 启动时自动处理未完成订单
将历史购买查询和未完成订单处理逻辑放在应用启动入口(如main方法或首页初始化),确保每次启动都能补全未完成的completePurchase操作,避免状态不一致。
内容的提问来源于stack exchange,提问作者Jay Mungara
相关产品推荐
相关产品推荐

