Реалізація сповіщень про закінчення підписки у мобільному додатку
Користувач забуває про підписку — факт. Автоматичне списання пройшло, сервіс продовжує працювати, але через місяць карта заблокована, платіж падає, а додаток мовчить. Людина уходить, думаючи, що підписка просто закінчилась. Грамотно вистроєна система сповіщень утримує цих користувачів ще до того, як платіж не пройшов.
Серверні події vs локальні сповіщення
Перше питання при реалізації: звідки знати, коли підписка істікає? Для In-App Purchase (StoreKit) Apple присилає події на сервер через App Store Server Notifications V2. Для власних серверних підписок — логіка на вашій стороні.
StoreKit 2 / App Store Server Notifications V2: Apple шле RENEWAL та EXPIRED події на ваш сервер. При отриманні DID_FAIL_TO_RENEW — перший сигнал, що потрібно відправити push. При GRACE_PERIOD_EXPIRED — останній шанс. Важливо: Apple самостійно відправляє деякі системні сповіщення, але покладатися тільки на них не можна — бізнес-логіку напоминань будувати потрібно самостійно.
// Серверна нотифікація V2 (декодований payload)
{
"notificationType": "DID_FAIL_TO_RENEW",
"subtype": "GRACE_PERIOD",
"data": {
"bundleId": "com.example.app",
"transactionInfo": { ... }
}
}
Локальні сповіщення: підходять тільки якщо сервера нема зовсім, або для offline-сценаріїв. UNUserNotificationCenter з UNCalendarNotificationTrigger — плануємо на дату expiresDate - 3 дні. Проблема: якщо користувач продовжив підписку через веб або інший пристрій, локальне сповіщення все одно спрацює. Без синхронізації з сервером це дає помилкові спрацьовування.
Ланцюжок напоминань
Одне сповіщення — погана стратегія. Робоча схема для B2C:
- За 7 днів до закінчення: «Підписка істікає 15 квітня — продовжте, щоб не втратити дані»
- За 1 день: конкретний заклик з deeplink на екран управління підпискою
- У день закінчення: сповіщення з обмеженим за часом пропозицією (якщо є)
- Через 3 дні після: реактивація зі знижкою (опціонально)
Deeplink в сповіщенні — обов'язковий. Push без дії втрачає конверсію. На iOS: UNNotificationAction з foreground — відкриває додаток та передає userInfo. На Android: PendingIntent з потрібним Intent.
// iOS: обробка tap по сповіщенню про підписку
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse) async {
let info = response.notification.request.content.userInfo
if info["type"] as? String == "subscription_expiry" {
NavigationRouter.shared.navigate(to: .subscriptionManagement)
}
}
На Android через FCM аналогічно: в data payload передаємо type: subscription_expiry, у FirebaseMessagingService.onMessageReceived маршрутизуємо.
Сегментація та тайминг
Користувач з місячною підпискою та користувач з річною — різні ситуації. Для місячної підписки 7-денне вікно — це 25% залишившегося терміну, що агресивно. Річна — 7 днів з 365, нормально.
Часовий пояс користувача критичний: push в 3 ночи — це раздратування та відписка від сповіщень. Firebase FCM дозволяє задавати delivery_time з урахуванням локального часу пристрою. Для APNs це робиться на рівні сервера через планувальник завдань з урахуванням timezone користувача.
Процес
Аудит поточної системи підписок: StoreKit / серверні / гібрид.
Настройка App Store Server Notifications V2 або серверних вебхуків для тригерів закінчення.
Реалізація ланцюжка push-сповіщень з deeplink на потрібний екран.
Тестування на sandbox-окруженні StoreKit (Xcode → StoreKit Testing) та бойова перевірка FCM.
Орієнтири за терміни
Інтеграція з готовим сервером сповіщень та StoreKit 2 — 2–3 дні. Реалізація серверної логіки з нуля, планувальником завдань та сегментацією користувачів — до 1 тижня.







