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