Реализация Grace Period при неудачном списании подписки

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.

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

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

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

Услуги, которые мы предлагаем
Показано 1 из 1Все 1735 услуг
Реализация Grace Period при неудачном списании подписки
Средний
~2-3 дня
Часто задаваемые вопросы

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

Этапы разработки

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

  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    495

Реализация Grace Period при неудачном списании подписки

Grace Period — это временное окно, которое Apple и Google дают пользователю после неудачного списания: карта истекла, недостаточно средств, временный сбой банка. В течение grace period подписка считается активной. Задача разработчика — корректно читать этот статус и не отрезать пользователя от контента раньше времени.

Без реализации grace period приложение блокирует доступ сразу после неудачного списания. Пользователь обновляет карту, но уже ушёл — это прямые потери в retention.

Grace Period на iOS (StoreKit 2)

Apple автоматически активирует grace period если он включён в App Store Connect → Subscriptions → [Subscription Group] → Grace Period. Варианты длительности: 3, 6 или 16 дней.

Для чтения статуса используем Product.SubscriptionInfo.Status:

import StoreKit

func checkSubscriptionStatus(productId: String) async -> SubscriptionAccessLevel {
    guard let product = try? await Product.products(for: [productId]).first,
          let statuses = try? await product.subscription?.status else {
        return .notSubscribed
    }

    for status in statuses {
        switch status.state {
        case .subscribed:
            return .active

        case .inGracePeriod:
            // Списание не прошло, но grace period активен
            // Показываем мягкое предупреждение, не блокируем контент
            return .gracePeriod

        case .inBillingRetryPeriod:
            // Grace period истёк, Apple продолжает попытки списания (до 60 дней)
            // Контент НЕ доступен
            return .billingRetry

        case .expired, .revoked:
            return .notSubscribed

        default:
            continue
        }
    }
    return .notSubscribed
}

enum SubscriptionAccessLevel {
    case active, gracePeriod, billingRetry, notSubscribed
}

Что показывать пользователю в grace period

Ключевой принцип: не блокировать контент, но показывать мягкий баннер с призывом обновить платёжные данные. Агрессивный paywall в grace period — это плохой UX и нарушение гайдлайнов Apple.

// SwiftUI-баннер
if subscriptionStatus == .gracePeriod {
    GracePeriodWarningBanner(
        message: "Не удалось списать оплату. Обновите данные карты, чтобы сохранить доступ.",
        actionTitle: "Управление подпиской",
        action: { openManageSubscriptions() }
    )
}

// Открываем системный экран управления подписками
func openManageSubscriptions() {
    Task {
        try? await AppStore.showManageSubscriptions(in: windowScene)
    }
}

Grace Period на Android (Google Play Billing)

В Google Play Billing grace period реализуется через purchaseState и isAutoRenewing:

// Через RTDN (Real-Time Developer Notifications) или PurchasesUpdatedListener
// Google отправляет SubscriptionNotification.SUBSCRIPTION_IN_GRACE_PERIOD

fun handleSubscriptionNotification(notification: SubscriptionNotification) {
    when (notification.notificationType) {
        SubscriptionNotification.SUBSCRIPTION_IN_GRACE_PERIOD -> {
            // Контент доступен, показываем предупреждение
            showGracePeriodWarning()
        }
        SubscriptionNotification.SUBSCRIPTION_EXPIRED -> {
            // Grace period истёк
            revokeAccess()
        }
    }
}

Серверная обработка предпочтительна: RTDN приходит на backend через Pub/Sub, бэкенд обновляет статус пользователя, мобильный клиент получает актуальный статус при следующем запросе.

Серверная валидация — надёжнее клиентской

Клиентская проверка через StoreKit — удобна для UI, но не должна быть единственным источником истины. Правильная архитектура:

  1. Сервер получает транзакции через App Store Server Notifications V2 (тип DID_FAIL_TO_RENEW, GRACE_PERIOD_EXPIRED)
  2. Обновляет поле subscription_status в базе
  3. Мобильный клиент при запросе /me/subscription получает актуальный статус

Это единственный надёжный способ, если пользователь открыл приложение через несколько дней — кэш StoreKit мог не обновиться.

Что входит в работу

  • Включение grace period в App Store Connect / Google Play Console
  • Клиентское чтение inGracePeriod / inBillingRetryPeriod (StoreKit 2)
  • UI-баннер с предупреждением и ссылкой на управление подпиской
  • Логика доступа к контенту: grace = разрешено, billingRetry = заблокировано
  • Опционально: серверная обработка App Store Server Notifications

Сроки

2–3 дня — клиентская часть с UI-логикой. С серверной обработкой уведомлений: 4–5 дней. Стоимость рассчитывается индивидуально.