Как успешно завершить покупку в приложении с помощью flutter на Android?

#android #flutter #google-play #in-app-purchase #in-app-billing

#Android #flutter #google-play #покупка в приложении #биллинг в приложении

Вопрос:

Чего я хочу

Я хочу интегрировать покупки в приложении Google Play в свое приложение flutter, продукт, который я хочу продать, является расходным материалом. Прямо сейчас я использую in_app_purchase: (0.3.4 16) пакет.

Что я сделал

  • Создайте продукт в консоли разработчика Google Play
  • Настройте проект в соответствии с документацией пакета in_app_purchase
  • Реализована некоторая логика для покупки расходных материалов (см. Ниже)
  • Создал альфа-релиз и загрузил его на альфа-тестовый трек, чтобы протестировать его
  • Создал новую учетную запись Google на моем телефоне разработчика, зарегистрировал ее как тестер и загрузил альфа-версию
  • Приобретенный с помощью «тестовой карты, всегда одобряется»
  • Приобретено с моей учетной записью 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,
  );
}
 

Ответ №1:

Решение состоит в том, чтобы не вызывать completePurchase(...) метод для расходных покупок. По умолчанию библиотека использует покупку для вас, которая неявно действует как вызов completePurchase(...) .

Предыстория

Вызов InAppPurchaseConnection.instance.buyConsumable(...) имеет необязательный логический параметр autoConsume , который всегда true . Это означает, что на Android покупка расходуется прямо перед обратным вызовом на purchaseUpdatedStream . В документации к completePurchase методу говорится следующее:

[Покупка потребления] действует как неявная [Полная покупка] на Android

Код для устранения проблемы

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