我想要的
我想在我的Flutter应用程序中集成Google Play应用内购买功能,我想销售的产品是可消耗品。目前我正在使用in_app_purchase: (0.3.4+16)
包。
我的操作
- 在Google Play开发者控制台中创建产品。
- 按照in_app_purchase包的文档设置项目。
- 实现了一些逻辑来购买可消耗物品(见下文)。
- 构建了一个Alpha版本并将其上传到Alpha测试轨道以进行测试。
- 在我的开发者手机上创建了一个新的Google帐户,将其注册为测试人员,并下载了Alpha版本。
- 使用“测试卡,始终批准”进行购买。
- 使用我的PayPal账户进行购买。
期望和实际结果
我期望支付能够正常工作,并且所有API调用都能返回OK。
当我在手机上启动购买流程时,购买流程开始并且我可以选择所需的付款方式。在我接受付款后,如预期地调用了_listenToPurchaseUpdated(...)
方法。
然而,调用InAppPurchaseConnection.instance.completePurchase(p)
返回一个BillingResponse.developerError
,并且我收到以下调试消息:
W/BillingHelper: Couldn't find purchase lists, trying to find single data.
I/flutter: result: BillingResponse.developerError (Purchase is in an invalid state.)
这个错误在使用“测试卡始终批准”或者使用PayPal进行真实交易时会出现。对于PayPal购买,我收到了一封确认电子邮件,说明交易成功。 文档中指出:
警告!在购买后的3天内未调用此方法并获得成功响应将导致Android退款。
问题概述
如何使调用 InAppPurchaseConnection.instance.completePurchase(p)
方法返回成功结果?
购买实现
设置应用内购买的代码如文档中所示实现:
InAppPurchaseConnection.enablePendingPurchases();
Stream<List<PurchaseDetails>> purchaseUpdated = InAppPurchaseConnection.instance.purchaseUpdatedStream;
_subscription = purchaseUpdated.listen(_listenToPurchaseUpdated, onDone: () {
_subscription.cancel();
}, onError: (error) {
// handle error here.
});
...
Future<void> _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) async {
for (var p in purchaseDetailsList) {
// Code to validate the payment
if (!p.pendingCompletePurchase) continue;
var result = await InAppPurchaseConnection.instance.completePurchase(p);
if (result.responseCode != BillingResponse.ok) {
print("result: ${result.responseCode} (${result.debugMessage})");
}
}
}
购买可消耗品时,我有一种方法来查询产品详细信息并调用
buyConsumable(...)
。Future<bool> _buyConsumableById(String id) async {
final ProductDetailsResponse response = await InAppPurchaseConnection
.instance
.queryProductDetails([id].toSet());
if (response.notFoundIDs.isNotEmpty || response.productDetails.isEmpty) {
return false;
}
List<ProductDetails> productDetails = response.productDetails;
final PurchaseParam purchaseParam = PurchaseParam(
productDetails: productDetails[0],
);
return await InAppPurchaseConnection.instance.buyConsumable(
purchaseParam: purchaseParam,
);
}