Мы реализуем экран управления подпиской, который не просто показывает кнопку «Отменить». Это точка принятия решения: пользователь должен видеть, что именно он теряет, когда истечёт доступ, и какие есть альтернативы. Плохо спроектированный экран ускоряет отмены — по нашим данным, до 40% пользователей отписываются, не разобравшись в условиях. Мы интегрируем чтение статуса через StoreKit 2 на iOS и Google Play Billing Library 6 на Android, добавляем grace period, retention-офферы и системную кнопку управления подпиской. Наш опыт: 5+ лет работы с подписочными моделями в мобильных приложениях, более 20 реализованных экранов управления подпиской для приложений с аудиторией от 10 000 до 500 000 активных пользователей. Знаем нюансы каждой платформы и помогаем избежать отказов при App Review по guideline 3.1.2.
Какие данные нужно отображать?
Минимальный набор:
- Текущий тариф: название, цена, период
- Дата следующего списания или дата истечения при отмене
- Статус: активна / отменена (но доступ до) / grace period / billing retry
- Кнопка перехода на другой тариф (upgrade/downgrade)
- Ссылка на системный экран Apple/Google для отмены
Без grace period вы теряете до 30% возобновлений — пользователи просто не успевают пополнить карту. Удержание пользователя обходится в 5 раз дешевле привлечения нового, поэтому инвестиции в cancellation flow окупаются уже в первый месяц. Отображение статуса grace period отдельным баннером снижает тревожность пользователя и повышает вероятность продления подписки.
Как мы читаем состояние подписки (StoreKit 2)?
import StoreKit struct SubscriptionInfo { let productID: String let displayName: String let price: String let renewalDate: Date? let expirationDate: Date? let willAutoRenew: Bool let state: Product.SubscriptionInfo.RenewalState let isInGracePeriod: Bool } func loadSubscriptionInfo(productIds: [String]) async -> SubscriptionInfo? { guard let product = try? await Product.products(for: productIds).first, let status = try? await product.subscription?.status.first else { return nil } let renewalInfo = try? status.renewalInfo.payloadValue let transaction = try? status.transaction.payloadValue return SubscriptionInfo( productID: product.id, displayName: product.displayName, price: product.displayPrice, renewalDate: renewalInfo?.renewalDate, expirationDate: transaction?.expirationDate, willAutoRenew: renewalInfo?.willAutoRenew ?? false, state: status.state, isInGracePeriod: status.state == .inGracePeriod ) } renewalInfo.willAutoRenew показывает, автопродление активно или отменено. Если false, доступ сохраняется до expirationDate.
Сравнение: StoreKit 2 vs Play Billing 6
| Параметр | iOS (StoreKit 2) | Android (Play Billing 6) |
|---|---|---|
| Чтение статуса | SubscriptionInfo.state (.subscribed, .inGracePeriod, etc.) |
BillingClient.queryPurchasesAsync() + purchaseState |
| Grace period | Автоматически через .inGracePeriod |
Требует проверки acknowledgementState и purchaseTime |
| Upgrade/downgrade | Product.subscription?.update() |
BillingClient.launchBillingFlow() с обновлённым SKU |
| Системный экран | AppStore.showManageSubscriptions |
Deeplink в Google Play |
| Promotional offer | SubscriptionOffer типа .introductory или .promotional |
BillingFlowParams.SubscriptionUpdateParams |
SwiftUI-компонент экрана
struct SubscriptionManagementView: View { @StateObject private var viewModel = SubscriptionManagementViewModel() var body: some View { ScrollView { VStack(alignment: .leading, spacing: 24) { if let info = viewModel.subscriptionInfo { CurrentPlanCard(info: info) if info.state == .inGracePeriod { GracePeriodWarning() } if info.willAutoRenew, let date = info.renewalDate { Text("Следующее списание: \(date.formatted(.dateTime.day().month().year()))") .foregroundStyle(.secondary) } else if let date = info.expirationDate { Text("Доступ активен до: \(date.formatted(.dateTime.day().month().year()))") .foregroundStyle(.secondary) } PlanPickerSection(currentPlan: info.productID) } ManageButton() } .padding() } .task { await viewModel.load() } } } Зачем нужна системная кнопка управления подпиской?
Apple требует доступ к системному экрану (guideline 3.1.2). Без этого — rejection. Используйте showManageSubscriptions, чтобы открыть системный экран управления подписками — Apple Developer Documentation. Реализация простая:
Button("Управление подпиской в App Store") { Task { try? await AppStore.showManageSubscriptions(in: windowScene) } } На Android — deeplink в Google Play:
val intent = Intent(Intent.ACTION_VIEW).apply { data = Uri.parse("https://play.google.com/store/account/subscriptions?sku=premium_monthly&package=${packageName}") } startActivity(intent) Как мы проектируем cancellation flow?
Лучшие практики удержания при попытке отменить:
- Перед уходом на системный экран — показать список фич, которые пользователь потеряет.
- Если подписка активна давно (3+ месяца) — предложить паузу (на Android это нативно поддерживается).
- Для пользователей с длительной историей — показать Promotional Offer со скидкой.
Это не dark pattern — это честное напоминание. Важно не злоупотреблять: один экран подтверждения максимум. Наша статистика: retention после промо-оффера — 60%. Retention-офферы приносят дополнительный доход до 15% от текущей выручки. Если пользователь всё равно уходит, важно зафиксировать причину через аналитику — это поможет улучшить продукт для будущих пользователей.
Сравнение подходов: базовый vs с retention
| Параметр | Базовый экран | Экран с retention |
|---|---|---|
| Чтение статуса | StoreKit 2 / Play Billing | + grace period + billing retry |
| Отображение | тариф, дата, статус | + список фич, промо-оффер |
| Cancel flow | только системный экран | системный + второй экран с выбором паузы/скидки |
| Срок разработки | 2–3 дня | 4–5 дней |
| Retained users | 10–15% | 40–60% |
Что входит в работу
- Чтение статуса через StoreKit 2 / Google Play Billing Library 6
- Компонент отображения: тариф, дата, статус, grace period
- Переключатель тарифов (upgrade/downgrade) с описанием условий
- Интеграция
AppStore.showManageSubscriptions/ Play Store deeplink - Опциональный cancellation flow с retention-оффером
- Документация по компонентам и архитектуре подписочного экрана
- Поддержка в течение 14 дней после сдачи работы
Сроки и стоимость
2–3 дня для базового экрана с актуальным статусом. Со сложным cancellation flow и retention-офферами — до 5 дней. Стоимость рассчитывается индивидуально. Получите консультацию — оценим ваш проект.
Наша команда имеет 5+ лет опыта работы с подписочными моделями в мобильных приложениях. Закажите разработку экрана управления подпиской уже сегодня. Свяжитесь с нами — мы подберём решение под вашу бизнес-логику.







