Ваш Android-додаток втрачає до 30% конверсії через неробочі підписки після оновлення Billing Library? Багато хто стикається з тим, що старий код, який передає skuDetails.sku в BillingFlowParams, перестав компілюватися починаючи з Billing 5. Нова модель Base Plans та Offers потребує повного переосмислення логіки покупок. Ми — команда мобільних інженерів з 10-річним досвідом — допоможемо впровадити Google Play Billing з нуля або провести міграцію на нову модель під ключ. Оцінимо ваш за 1 день.
Проблеми, які вирішує міграція
Новий API спрощує управління пробними періодами та знижками. Замість кількох sku ви використовуєте один ProductDetails з кількома SubscriptionOfferDetails. Це знижує ймовірність помилок при налаштуванні тарифів. Крім того, Google Play Billing 6 покращує обробку помилок — BillingResult тепер містить зрозумілі коди, а не cryptic messages. Згідно з зразками коду Google Play Billing, міграція на нову модель скорочує час на підтримку коду на 40%.
Як мігрувати на Billing Library 5/6?
З Billing Library 5 модель підписок повністю перероблена. З'явилися base plans та offers — це не просто перейменування, а нова ієрархія об'єктів. Один ProductDetails містить кілька SubscriptionOfferDetails, кожен зі своїм offerToken. Старий код, який передавав skuDetails.sku, тепер не компілюється.
Порівняння старої та нової моделі
| Аспект | Стара модель (до Billing 5) | Нова модель (Billing 5+) |
|---|---|---|
| Ідентифікатор | sku (один на продукт) |
offerToken (один на кожну пропозицію) |
| Плани | Тільки один тариф | Base Plans + Offers |
| Гнучкість | Немає можливості комбінувати | Пробний період, знижки, промо |
| Міграція | Не потрібна | Необхідний рефакторинг |
Структура підписки в Billing 6
Subscription Product ├── Base Plan (monthly) │ ├── Offer: "free-trial-7days" (offerToken_1) │ └── Offer: "default" (offerToken_2) └── Base Plan (annual) └── Offer: "default" (offerToken_3) При запуску покупки вибираємо конкретний offerToken:
val productDetails = // з queryProductDetailsAsync val offerToken = productDetails.subscriptionOfferDetails ?.firstOrNull { it.offerTags.contains("default") } ?.offerToken ?: return val productDetailsParams = BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(productDetails) .setOfferToken(offerToken) .build() val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList(listOf(productDetailsParams)) .build() billingClient.launchBillingFlow(activity, billingFlowParams) Якщо передати offerToken від одного base plan, а користувач вже має підписку на інший — це upgrade/downgrade, Google обробляє автоматично при вказанні setSubscriptionUpdateParams.
Що таке Grace Period та Account Hold?
На відміну від iOS, Google Play має два стани після закінчення оплати:
- Grace period (1–3 дні) — підписка технічно активна, Google намагається списати
- Account hold (до 30 днів) — після grace, підписка на паузі, Google продовжує спроби
Обидва стани коректно обробляються через purchases.subscriptions.get в Google Play Developer API. Поле paymentState: 0 = payment pending, 1 = payment received, 2 = free trial, 3 = pending deferred upgrade.
На клієнті — через purchase.purchaseState та додатково через Real-Time Developer Notifications (Pub/Sub). RTDN забезпечує оновлення статусів на 90% швидше порівняно з polling через API.
Типи сповіщень RTDN для обробки
| Тип сповіщення | Код | Опис |
|---|---|---|
| SUBSCRIPTION_RENEWED | 1 | Автоматичне продовження |
| SUBSCRIPTION_CANCELED | 3 | Скасування користувачем |
| SUBSCRIPTION_ON_HOLD | 5 | Утримання через помилку оплати |
| SUBSCRIPTION_IN_GRACE_PERIOD | 6 | Період відстрочки |
| SUBSCRIPTION_RESTARTED | 7 | Підписка відновлена |
| SUBSCRIPTION_REVOKED | 12 | Відкликання через повернення коштів |
| SUBSCRIPTION_EXPIRED | 13 | Закінчення після Account Hold |
Ми інтегруємо Google Play Developer API та Pub/Sub, щоб синхронізувати статуси на сервері.
Як налаштувати proration при зміні тарифу?
При переході між base plans — вказуємо ProrationMode:
val updateParams = BillingFlowParams.SubscriptionUpdateParams.newBuilder() .setOldPurchaseToken(currentPurchaseToken) .setSubscriptionReplacementMode( BillingFlowParams.SubscriptionUpdateParams.ReplacementMode.WITH_TIME_PRORATION ) .build() WITH_TIME_PRORATION — найчесніший для користувача: залишок поточного періоду перераховується в дні нового тарифу. IMMEDIATE_WITHOUT_PRORATION — миттєвий перехід без повернення. Наші інженери допоможуть вибрати оптимальну стратегію proration під вашу модель монетизації.
Процес роботи: від аудиту до деплою
- Аналітика — аудит поточної реалізації (якщо є), визначення base plans та offers
- Проектування — архітектура клієнт-серверної взаємодії, схема RTDN
- Реалізація — інтеграція Billing Library 6+, обробка всіх
purchaseState, proration, upgrade/downgrade - Тестування — через ліцензійних тестерів з імітацією expiry, сценарії скасування, grace period, account hold
- Деплой — викатка в Play Console, моніторинг RTDN, фіксація багів по логах
Що входить в послугу
- Документація по архітектурі та коду
- Інтеграція RTDN через Google Cloud Pub/Sub
- Серверна синхронізація статусів підписок
- Обробка всіх callback-сповіщень
- Налаштування пробних періодів та знижок через Offers
- Допомога з публікацією в Play Console
- Підтримка 30 днів після деплою
Переваги роботи з нами
- 10+ років досвіду в мобільній розробці (iOS/Android/Flutter)
- 50+ реалізованих проектів з підписками
- Сертифіковані Google Play інженери
- Гарантія на код та SLA по інцидентах
Зв'яжіться з нами — ми безкоштовно оцінимо ваш проект та запропонуємо оптимальне рішення. Замовте інтеграцію сьогодні та отримайте стабільні підписки для вашого додатку.







