Реалізація Google Play Billing (одноразові покупки) для Android
Google Play Billing Library 6+ (з 2023 року обов'язкова для нових додатків, з 2024 — для оновлень) переробила API покупок. BillingClient.queryPurchasesAsync замінив синхронний queryPurchases, з'явився PendingPurchasesParams для відстрочених транзакцій. Додатки на BillingClient 4 та нижче відхиляються при публікації.
One-time products: INAPP vs DURABLE
В Play Billing 6+ одноразові покупки діляться на два підтипи:
- INAPP (старий тип) — consumables і non-consumables в одній кошику
- DURABLE — явно non-consumable, новий тип з BillingClient 6
На практиці для «приховати рекламу» і «відкрити рівні» використовуємо ProductType.INAPP з acknowledged-статусом як маркером володіння.
Acknowledgement — де все падає
Кожна покупка повинна бути підтверджена впродовж 3 днів через acknowledgePurchase() або consumePurchase() (для consumables). Якщо не підтвердити — Google автоматично повертає гроші та відкликає покупку. Це не очевидно з документації.
val billingClient = BillingClient.newBuilder(context)
.setListener { billingResult, purchases ->
purchases?.forEach { purchase ->
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED) {
if (!purchase.isAcknowledged) {
val params = AcknowledgePurchaseParams.newBuilder()
.setPurchaseToken(purchase.purchaseToken)
.build()
billingClient.acknowledgePurchase(params) { result ->
if (result.responseCode == BillingClient.BillingResponseCode.OK) {
unlockFeature(purchase.products.first())
}
}
}
}
}
}
.enablePendingPurchases(
PendingPurchasesParams.newBuilder()
.enableOneTimeProducts()
.build()
)
.build()
enablePendingPurchases() тепер обов'язковий. Без нього BillingClient.startConnection() кидає виняток. Pending-покупки (оплата готівкою через партнерів Google Pay в деяких регіонах) переходять у PURCHASED не одразу — потрібно слухати оновлення через PurchasesUpdatedListener.
Відновлення покупок при переустановці
При переустановці додатку покупки відновлюються через queryPurchasesAsync(QueryPurchasesParams). Викликайте при кожному старті:
val params = QueryPurchasesParams.newBuilder()
.setProductType(BillingClient.ProductType.INAPP)
.build()
billingClient.queryPurchasesAsync(params) { billingResult, purchaseList ->
purchaseList.filter {
it.purchaseState == Purchase.PurchaseState.PURCHASED && it.isAcknowledged
}.forEach { restoreAccess(it) }
}
Серверна верифікація
Для серверних додатків — purchaseToken надсилаємо на свій бекенд, який через Google Play Developer API (purchases.products.get) перевіряє purchaseState і acknowledgementState. Тільки після цього розблоковуємо контент у БД.
Терміни — 2–3 дні: інтеграція Billing Library 6, обробка всіх станів покупки, серверна верифікація, тести через Google Play Console License Testing.







