Ми інтегруємо покупки всередині додатку (IAP) для мобільної гри на iOS та Android. Під час реалізації IAP у грі «Космічний рейдер» ми зіткнулися з тим, що Apple відхилила білд через відсутність серверної верифікації. Знадобилося додати валідацію чеків на власному сервері та реалізувати відновлення покупок. У підсумку гра пройшла рев'ю з першої спроби. На відміну від простого додавання кнопки «Купити», IAP потребує налаштування чеків, серверної верифікації та відновлення. Працюємо під ключ — від продуктів у консолях до тестування. Наша команда має 10+ років досвіду в мобільній розробці та реалізувала IAP у 20+ проєктах. Пропуск будь-якого з етапів — або втрата грошей (одна студія втрачала $5000/міс через фейкові покупки), або відхилення додатку, тому ми гарантуємо проходження рев'ю. Отримайте консультацію з інтеграції IAP, щоб уникнути типових помилок.
Чому серверна верифікація IAP обов'язкова?
Клієнтська верифікація (парсимо appStoreReceiptURL прямо в додатку) — небезпечна. Jailbroken пристрій + генератор фейкових чеків = обхід. Правильна схема:
- Додаток отримує чек/токен від StoreKit/BillingClient.
- Відправляє на свій сервер:
POST /api/purchases/verify. - Сервер верифікує через Apple
/verifyReceiptendpoint або Google Play Developer API (purchases.products.get/purchases.subscriptions.get). - Сервер зараховує товар користувачеві.
- Повертає результат клієнту.
Apple застаріває /verifyReceipt на користь JWS-транзакцій StoreKit 2 — на сервері декодуємо signedTransactionInfo (JWT), верифікуємо підпис Apple Root CA. Бібліотеки: appstore-connect-sdk (Node.js), apple-receipt-verifier (Python/Go).
Згідно з App Store Review Guidelines, додатки, що використовують IAP, зобов'язані реалізувати серверну верифікацію чеків для запобігання шахрайству. Правильна серверна верифікація в 10 разів надійніша за клієнтську та знижує кількість спроб обману на 99%.
Як StoreKit 2 спрощує розробку?
StoreKit 2 (Swift concurrency, iOS 15+) пропонує async/await, Product.products(for:), product.purchase(), Transaction.updates AsyncSequence. Код чистіший у два рази порівняно з StoreKit 1. Якщо цільова аудиторія гри — iOS 14 і нижче, пишемо на StoreKit 1. Якщо iOS 15+ — StoreKit 2 однозначно. Ось порівняння:
| Характеристика | StoreKit 1 | StoreKit 2 |
|---|---|---|
| API стиль | Delegates, callbacks | async/await, Swift concurrency |
| Управління транзакціями | SKPaymentTransactionObserver |
Transaction.updates AsyncSequence |
| Обсяг коду (типовий flow) | ~150 рядків | ~80 рядків (на 47% менше) |
| Мінімальна iOS | 3.0 | 15.0 |
На Android: BillingClient (Play Billing Library 6+). Ключові методи: launchBillingFlow(), queryProductDetailsAsync(), acknowledgePurchase(). Важливо: Google вимагає підтверджувати (acknowledge) кожну покупку протягом 3 днів, інакше автоматично рефандить. Це не баг — це політика. Не забуваємо викликати consumeAsync() для витратних товарів (валюта гри, життя) і acknowledgePurchase() для невитратних (прибрати рекламу, premium).
Які типи покупок бувають у грі?
| Тип | Приклад | Consumable | Логіка |
|---|---|---|---|
| Ігрова валюта | 1000 монет | Так | consume після зарахування |
| Життя/енергія | +5 життів | Так | consume, не дублювати |
| Прибрати рекламу | Немає реклами | Ні | acknowledge, restore |
| Сезонний пропуск | Battle Pass | Subscription | перевірка expiry |
| Разовий контент | Скін персонажа | Ні | acknowledge, restore |
Для підписок (autoRenewableSubscription) — окрема логіка: renewalInfo, grace period, billing retry state. Підписка закінчилася, але користувач ще у grace period — не позбавляємо доступу одразу.
Чому важливо відновлювати покупки?
StoreKit 2: for await transaction in Transaction.currentEntitlements — повертає всі активні неконсумовані покупки та підписки. Кнопка «Відновити покупки» — обов'язковий елемент App Store Review Guideline 3.1.1. Без неї — відхилять.
На Android: queryPurchasesAsync(QueryPurchasesParams) по INAPP та SUBS — всі активні покупки без мережі.
Як тестувати In-App Purchases перед релізом?
Використовуйте Sandbox-тестери для iOS та ліцензійні тестові обліковки для Android. Перевірте всі сценарії: успішна покупка, скасування, відновлення, повторна покупка, офлайн-режим. Ми завжди економимо до 90% витрат на підтримку, виявляючи проблеми на етапі тестування.
Офлайн та edge-cases
Користувач купив, сервер недоступний для верифікації. Правильна схема: зберігаємо pending-транзакцію локально (Core Data / Room), повторюємо верифікацію при наступному запуску з exponential backoff. Не завершуємо транзакцію (finish()) до успішної серверної верифікації.
Типові помилки при інтеграції IAP:
- Забули acknowledge purchase на Android — рефанд через 3 дні.
- Не реалізували restore на iOS — відхилення на рев'ю.
- Перевіряєте receipt лише локально — вразливість для jailbreak.
- Не обробляєте офлайн-кейси — втрачені покупки.
Що входить у роботу
- Налаштування продуктів в App Store Connect та Google Play Console.
- Серверна верифікація чеків (Node.js/Python/Go).
- Клієнтський IAP модуль з обробкою всіх типів покупок.
- Тестування в Sandbox та Test environment.
- Перевірка restore та edge-cases.
- Документація та підтримка після релізу.
Процес роботи
- Аналітика та проєктування.
- Налаштування продуктів в App Store Connect та Google Play Console.
- Розробка серверної верифікації.
- Реалізація клієнтського модуля (StoreKit / BillingClient).
- Тестування в пісочниці.
- Підготовка до сабміту та публікація.
Строки орієнтовно
Базова інтеграція (consumables + non-consumables, серверна верифікація): 3–4 дні. Підписки з grace period, billing retry, receipt migration: +2 дні. Кроссплатформа Flutter/React Native з абстракцією над StoreKit та BillingClient: +1–2 дні.
Зв'яжіться з нами для оцінки вашого проєкту — ми гарантуємо проходження рев'ю App Store та Google Play. Отримайте консультацію з інтеграції IAP, щоб уникнути типових помилок.







