如何在安卓上使用Flutter成功完成应用内购买?

4

我想要的

我想在我的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,
  );
}
1个回答

4
解决方法是不要为可消耗的购买调用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})");
    }
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接