android - 如何在 Android 上使用 Flutter 成功完成应用内购买?
问题描述
我想要的是
我想将 Google Play 在应用购买中集成到我的 Flutter 应用中,我要销售的产品是消耗品。现在我正在使用这个in_app_purchase: (0.3.4+16)
包。
我做了什么
- 在 google play 开发者控制台中创建产品
- 根据 in_app_purchase 包的文档设置项目
- 实现了一些购买消耗品的逻辑(见下文)
- 构建了一个 alpha 版本并将其上传到 alpha 测试轨道以进行测试
- 在我的开发者手机上创建了一个新的谷歌帐户,将其注册为测试者并下载了 alpha 版本
- 用“测试卡,总是批准”购买
- 使用我的 PayPal 帐户购买
预期和实际结果
我希望付款能够正常工作,并且所有 api 调用都能正常返回。
当我在手机上开始购买时,购买流程开始,我可以选择所需的付款方式。在我接受付款后_listenToPurchaseUpdated(...)
,按预期调用该方法。但是,调用InAppPurchaseConnection.instance.completePurchase(p)
返回 aBillingResponse.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,
);
}
解决方案
解决方法是不调用completePurchase(...)
消耗品购买的方法。默认情况下,库会为您使用购买,这隐含地充当对completePurchase(...)
.
背景
调用InAppPurchaseConnection.instance.buyConsumable(...)
有一个可选的布尔参数autoConsume
,它总是true
. 这意味着,在 android 上,购买是在回调到purchaseUpdatedStream
. 该completePurchase
方法的文档说明如下:
[consumePurchase] 在 Android 上充当隐式 [completePurchase]
解决问题的代码
Future<void> _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) async {
for (var p in purchaseDetailsList) {
// Code to validate the payment
if (!p.pendingCompletePurchase) continue;
if (_isConsumable(p.productID)) continue; // Determine if the item is consumable. If so do not consume it
var result = await InAppPurchaseConnection.instance.completePurchase(p);
if (result.responseCode != BillingResponse.ok) {
print("result: ${result.responseCode} (${result.debugMessage})");
}
}
}
推荐阅读
- codeigniter - 将结果中的两行或多行合并为 CI 活动记录上的单个结果
- python - TypeError: with_column() 需要 3 到 4 个位置参数,但给出了 5 个(python)
- r - 选择具有相应位置的数据帧的 p 最高值
- node.js - 如何通过 Puppeteer 和 Request(http 模块)的代理在 Google Cloud App Engine 上启用传出 HTTP 连接的传出请求?
- vue.js - Vuex。无法访问对象变量
- python - 从 pandas 列中解压缩可变长度字典并创建单独的列
- r - 轴极端处的轴刻度线与面板边框不对齐
- css - css 的某些部分在添加 flex 后渲染
- python - 为什么我的查询不适用于 room.slug
- css - 如何在 TYPO3 10 的文件中设置安全策略指令 style-src