Warm tip: This article is reproduced from serverfault.com, please click

其他-如何在Android上使用Flutter成功完成应用内购买?

(其他 - How to successfully complete an in app purchase using flutter on android?)

发布于 2020-12-01 10:36:57

我想要的是

我想将Google Play的应用程序购买集成到我的Flutter应用程序中,我要销售的产品是消耗品。现在我正在使用in_app_purchase: (0.3.4+16)包裹。

我做了什么

  • 在Google Play开发者控制台中创建产品
  • 根据in_app_purchase软件包的文档设置项目
  • 实施了一些购买易耗品的逻辑(见下文)
  • 构建了一个Alpha版本,并将其上传到Alpha测试轨道以对其进行测试
  • 在我的开发人员电话上创建了一个新的Google帐户,将其注册为测试人员并下载了Alpha版本
  • 购买带有“测试卡,总是会批准”
  • 使用我的PayPal帐户购买

预期和实际结果

我希望付款正常,并且所有api调用都可以返回。

当我在手机上发起购买时,购买流程开始,并且我可以选择所需的付款方式。我接受付款后_listenToPurchaseUpdated(...),按预期方式调用了该方法。但是,调用InAppPurchaseConnection.instance.completePurchase(p)返回a时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,
  );
}
Questioner
Bennik2000
Viewed
12
Bennik2000 2020-12-02 01:45:00

解决的办法是不调用completePurchase(...)耗材购买方法。默认情况下,图书馆会为你使用购买的商品,这暗中充当对的调用completePurchase(...)

背景

的调用InAppPurchaseConnection.instance.buyConsumable(...)具有一个可选的boolean参数autoConsume,该参数始终为true这意味着,在android上,购买是在回调到之前使用的purchaseUpdatedStreamcompletePurchase方法的文档说明如下:

[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})");
    }
  }
}