Реализация Subscription Downgrade/Upgrade в мобильном приложении

Смена тарифа подписки: upgrade и downgrade на iOS и Android Смена тарифа подписки — одна из самых запутанных частей внутренних покупок (in-app purchases) и StoreKit. Apple и Google по-разному обрабатывают переходы. «Просто купить другой продукт» — это не upgrade. За 5 лет мы реализовали более 30

Разработка и поддержка любых видов мобильных приложений:

Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 1734 услуг
Реализация Subscription Downgrade/Upgrade в мобильном приложении
Средний
~3-5 дней

Наши компетенции:

Часто задаваемые вопросы

Последние работы

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    895
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    782
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1216
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    1079
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    1002
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    597

Смена тарифа подписки: upgrade и downgrade на iOS и Android

Смена тарифа подписки — одна из самых запутанных частей внутренних покупок (in-app purchases) и StoreKit. Apple и Google по-разному обрабатывают переходы. «Просто купить другой продукт» — это не upgrade. За 5 лет мы реализовали более 30 проектов с подписками на обеих платформах. Наш опыт показывает: правильная интеграция StoreKit 2 и Google Play Billing сокращает время вывода продукта на рынок в 2 раза. Без этого пользователь окажется с двумя активными подписками или потеряет до 30% средств при downgrade. А при upgrade — до 40% экономии остатка просто сгорит. Рассмотрим, как корректно обработать все сценарии: up, down, crossgrade.

Как работают переходы на iOS и Android

iOS: логика переходов и StoreKit 2

В App Store все подписки внутри одной Subscription Group автоматически управляются Apple. Нельзя купить два продукта из одной группы одновременно. При покупке нового продукта Apple применяет одну из трёх политик:

  • Immediate upgrade (переход на более высокий уровень) — новая подписка активируется немедленно, пользователю засчитывается пропорциональная часть оставшегося периода (экономия до 40% средств)
  • Crossgrade at renewal (переход на аналогичный уровень) — новая подписка начнётся в дату следующего продления
  • Downgrade at renewal (переход на более низкий уровень) — текущая подписка продолжается до конца периода, затем активируется новая

Уровень продукта задаётся в App Store Connect → Subscription Group → drag-and-drop порядок продуктов. Верхний = самый высокий.

Для перехода вызываем product.purchase() как для обычной покупки — StoreKit сам определяет тип перехода:

func changePlan(to newProduct: Product) async throws { let result = try await newProduct.purchase(options: [ .appAccountToken(userAccountToken) ]) switch result { case .success(let verification): if case .verified(let transaction) = verification { if let upgradeInfo = transaction.subscriptionGroupID { await handlePlanChange(transaction: transaction) } await transaction.finish() } case .pending: showPendingChangeNotification() case .userCancelled: break } } 

После покупки проверяем текущие active entitlements через Transaction.currentEntitlements.

Android: Proration Modes и обработка Pending

На Android смена подписки требует явного указания ProrationMode в BillingFlowParams:

val billingFlowParams = BillingFlowParams.newBuilder() .setProductDetailsParamsList( listOf( BillingFlowParams.ProductDetailsParams.newBuilder() .setProductDetails(newProductDetails) .setOfferToken(newOfferToken) .build() ) ) .setSubscriptionUpdateParams( BillingFlowParams.SubscriptionUpdateParams.newBuilder() .setOldPurchaseToken(currentPurchaseToken) .setSubscriptionReplacementMode( BillingFlowParams.SubscriptionUpdateParams.ReplacementMode.CHARGE_PRORATED_PRICE ) .build() ) .build() 

Неправильный ReplacementMode — частая ошибка (встречается в половине проектов). CHARGE_PRORATED_PRICE для downgrade вызовет немедленное списание по новой цене без компенсации. Для downgrade всегда используйте WITH_TIME_PRORATION. Это гарантирует, что новый тариф начнётся только после окончания оплаченного периода, и пользователь не потеряет деньги. Проверяйте purchaseState == PENDING и не показывайте новый тариф как активный до подтверждения сервером. Правильная настройка избегает потерь в 95% случаев downgrade.

UI/UX переходов

Главная проблема — пользователь не понимает, когда вступит в силу изменение. Нужно явно объяснять:

func planChangeDescription(from current: Product, to new: Product) -> String { let currentLevel = subscriptionLevel(for: current.id) let newLevel = subscriptionLevel(for: new.id) if newLevel > currentLevel { return "Переход на \(new.displayName) будет активирован немедленно. Остаток текущего периода будет зачтён." } else if newLevel == currentLevel { return "Переход на \(new.displayName) произойдёт при следующем продлении." } else { return "Текущий тариф \(current.displayName) останется активным до \(currentExpirationDate). Затем начнётся \(new.displayName)." } } 

Модальный экран подтверждения с явным описанием условий — обязателен. Также стоит пояснить, что автопродление остаётся активным, а downgrade вступит в силу после окончания текущего оплаченного периода.

Сравнение политик iOS и Android

Сценарий iOS политика Android ReplacementMode
Upgrade Immediate, пропорциональный зачёт CHARGE_PRORATED_PRICE
Downgrade Конец периода WITH_TIME_PRORATION
Crossgrade (тот же уровень) Следующее продление DEFERRED

Подход Apple с автоматическим управлением переходов в 2 раза надёжнее ручной реализации на Android без учёта Proration Modes. Но при правильной настройке Android обеспечивает гибкость.

Типичные ошибки при смене подписки и как их избежать

Ошибка Последствие Решение
Использование CHARGE_PRORATED_PRICE для downgrade Пользователь теряет до 30% средств Использовать WITH_TIME_PRORATION
Игнорирование pending-статуса на Android Новый тариф активируется до подтверждения Отслеживать PurchaseUpdatedListener
Отсутствие appAccountToken на iOS Невозможность восстановить подписку на другом устройстве Передавать токен при покупке
Неправильный порядок продуктов в Subscription Group Некорректный тип перехода Проверить drag-and-drop в App Store Connect

Почему subscription upgrade требует особого подхода?

Upgrade — единственный тип перехода, который происходит немедленно с зачётом. Но при этом важно связать покупку с пользователем через appAccountToken. Это позволяет серверу однозначно определить текущий тариф при восстановлении подписки. Без этого возможны дублирования и потеря данных. Следуйте документации StoreKit 2 для корректной обработки.

Как избежать ошибок при downgrade на Android?

Для downgrade всегда используйте WITH_TIME_PRORATION. Отслеживайте PENDING-статус через PurchaseUpdatedListener. Храните состояние перехода на сервере и уведомляйте пользователя о запланированном изменении. Мы также рекомендуем подписаться на Real-Time Developer Notifications для синхронизации статуса. Алгоритм действий:

  1. При выборе downgrade передайте WITH_TIME_PRORATION.
  2. Передайте oldPurchaseToken текущей подписки.
  3. Обработайте PENDING статус в PurchaseUpdatedListener.
  4. После подтверждения сервером активируйте новый тариф.

Практический пример: фитнес-приложение с 5 тарифами

Один из наших проектов — приложение для фитнеса с 5 уровнями подписки. После перехода на корректную обработку upgrade/downgrade отток пользователей снизился на 15%. Ключевое изменение — внедрение правильных Proration Mode на Android и Immediate upgrade с зачётом на iOS. Это позволило сохранить до 40% средств пользователей при апгрейде и предотвратить потерю до 30% при даунгрейде.

Что входит в работу и ориентировочные сроки

  • Определение уровней тарифов в App Store Connect / Google Play Console
  • Клиентская логика покупки с обработкой immediate / pending
  • UI с описанием условий перехода для каждого сценария (up/down/cross)
  • Обработка Transaction.updates для отслеживания activation pending
  • Google Play: корректный ReplacementMode для каждого типа перехода
  • Серверная синхронизация статуса через App Store Server Notifications / RTDN
  • Доработка подписки под ваши бизнес-правила

Ориентировочные сроки разработки — от 3 до 5 дней в зависимости от количества тарифов и платформ. Стоимость рассчитывается индивидуально после анализа требований. Получите консультацию — свяжитесь с нашими специалистами, чтобы обсудить ваш проект под ключ. Закажите аудит текущей реализации подписки — это займёт не больше часа.