Реализация In-App Purchases (расходуемые покупки) для iOS

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Реализация In-App Purchases (расходуемые покупки) для iOS
Средняя
~2-3 рабочих дня
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1054
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

Реализация In-App Purchases (расходуемые покупки) для iOS

Consumable IAP — монеты, кристаллы, жизни, заряды — покупки, которые тратятся и покупаются снова. В отличие от non-consumable, Apple их не восстанавливает: купленные монеты, потраченные год назад, не вернуть через restoreCompletedTransactions. Ответственность за балансировку виртуальной валюты полностью на разработчике.

Главная проблема: двойное начисление

Consumable-транзакция должна быть обработана ровно один раз. Самый распространённый баг — начислять валюту в paymentQueue(_:updatedTransactions:) и вызывать finishTransaction в том же методе. Если приложение крашнет после начисления, но до finishTransaction — Apple повторно доставит транзакцию при следующем запуске, и пользователь получит монеты дважды.

Правильный порядок при серверной архитектуре:

  1. Получаем транзакцию в .purchased состоянии
  2. Отправляем transactionIdentifier + receipt на свой сервер
  3. Сервер идемпотентно начисляет валюту (проверяет transactionIdentifier в БД — если уже есть, не начисляет повторно)
  4. После успешного ответа сервера — finishTransaction

Без шага с идемпотентностью на сервере двойное начисление при краше или нестабильной сети неизбежно.

StoreKit 2 и consumables

В StoreKit 2 consumable-транзакции не попадают в Transaction.currentEntitlements — потому что у них нет «активного» состояния. Они появляются в Transaction.all (полная история), но после finish() — только если transactionID известен.

let result = try await product.purchase()
if case .success(let verification) = result,
   case .verified(let transaction) = verification {
    // Отправляем на сервер для начисления
    let credited = await creditOnServer(transactionId: transaction.id,
                                         receiptData: receiptData)
    if credited {
        await transaction.finish()
    }
    // Если сервер недоступен — не финишируем,
    // транзакция придёт снова при следующем запуске
}

Офлайн-сценарий

Для игр без постоянного бэкенда — локальное хранение баланса в Keychain с серверной верификацией при следующей онлайн-сессии. При этом транзакцию не финишируем до подтверждения. Но если пользователь никогда не выходит в онлайн — нужен таймаут и локальный fallback, иначе App Review это отклонит (гайдлайн 3.1.1 требует, чтобы купленный контент был доступен).

Тестирование edge cases

В Xcode StoreKit Testing (StoreKitTest framework) можно имитировать сбои транзакций:

let session = try SKTestSession(configurationFileNamed: "Products")
session.simulateAskToBuyInSandbox = false
// Форсируем ошибку для тестирования retry-логики
try session.failTransactionsEnabled = true

Обязательно покрываем: покупка при отсутствии интернета, краш между начислением и finish(), повторный запуск после краша, попытка купить при уже незавершённой транзакции в очереди.

Сроки — 2–3 дня: интеграция StoreKit 2, серверная часть с идемпотентным начислением, тесты на Sandbox.