Чому silent push не доходить: кейси з практики
Silent push — потужний інструмент фонової синхронізації, але реалізація повна підводних каменів. За статистикою, неправильне налаштування silent push призводить до 40% недоотриманих сповіщень на Android і до 60% на iOS у складних сценаріях. Один із наших клієнтів, сервіс доставки на 500 000 користувачів, зіткнувся з тим, що після оновлення на Android 13 фонові сповіщення перестали пробуджувати додаток — Doze Mode з новими обмеженнями блокував high-priority повідомлення через відсутність виклику setForegroundAsync в expedited worker. Ми переналаштували обробку й додали виклик — проблема вирішилася. У цій статті розберемо, як гарантовано налаштувати фонову синхронізацію без участі користувача, і покажемо, як уникнути типових помилок. Наш досвід — 10+ років у мобільній розробці, 50+ проєктів з push-інфраструктурою.
Silent Push на iOS: технічні нюанси
На iOS silent push вимагає прапора content-available: 1 у payload і ввімкненої Background Mode «Remote notifications» у Xcode Capabilities.
Payload APNs:
{
"aps": {
"content-available": 1
},
"sync_type": "messages",
"last_known_id": "msg_8823"
}
Без alert, без sound — чистий фоновий виклик. Обробка в AppDelegate:
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
guard let syncType = userInfo["sync_type"] as? String else {
completionHandler(.noData)
return
}
Task {
do {
let hasNewData = try await SyncManager.shared.sync(type: syncType)
completionHandler(hasNewData ? .newData : .noData)
} catch {
completionHandler(.failed)
}
}
}
Критичний момент: iOS дає близько 30 секунд на виконання. Якщо completionHandler не викликано — примусове завершення. Також iOS не гарантує доставку при низькому заряді батареї (Low Power Mode) і після примусового закриття додатка. Force quit повністю блокує silent push до ручного запуску — це документована поведінка iOS, обійти не можна. Докладніше в офіційній документації Apple.
Silent Push на Android: FCM Data Message та WorkManager
На Android роль silent push виконує FCM Data Message — він потрапляє в FirebaseMessagingService.onMessageReceived незалежно від стану додатка (якщо не вбитий системою Doze).
class AppFirebaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(message: RemoteMessage) {
val syncType = message.data["sync_type"] ?: return
val workRequest = OneTimeWorkRequestBuilder<SyncWorker>()
.setInputData(workDataOf("sync_type" to syncType))
.setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
.build()
WorkManager.getInstance(applicationContext).enqueue(workRequest)
}
}
setExpedited() запитує негайне виконання. На Android 12+ всередині expedited worker потрібно викликати setForegroundAsync(), інакше при довгій операції можливий ANR.
Doze Mode обмежує фонову активність. FCM high-priority повідомлення обходять Doze, якщо в payload вказати android.priority: "HIGH":
{
"message": {
"token": "device_fcm_token",
"android": {
"priority": "HIGH"
},
"data": {
"sync_type": "messages",
"payload": "{...}"
}
}
}
Додатково про Doze Mode
Doze Mode активується, коли пристрій неактивний і не підключений до зарядки. High-priority повідомлення обходять його, але при дуже частих запитах система може почати ігнорувати їх — дотримуйтесь інтервалів не менше 10 хвилин між silent push.
Як оновити badge без сповіщення користувача?
Популярний кейс — оновити цифру на іконці без показу сповіщення. На iOS через silent push:
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
if let badge = userInfo["badge"] as? Int {
UNUserNotificationCenter.current().setBadgeCount(badge) { _ in }
}
completionHandler(.newData)
}
На Android єдиного API немає — використовуйте бібліотеку ShortcutBadger або NotificationManagerCompat.setNumber(), але підтримка залежить від лончера (Samsung, Xiaomi, Huawei).
Обмеження та квоти
iOS 13+ ввів BGTaskScheduler і background processing quota. Якщо додаток занадто часто запитує фонове виконання без користі для користувача, система починає throttle-ити виклики. Виклик completionHandler(.noData) при відсутності нових даних критичний для коректної роботи системи квот. На Android аналогічний механізм — WorkManager стискає часті задачі. Дотримуйтесь інтервалів і використовуйте експоненційну затримку при помилках.
Порівняння платформ
| Характеристика |
iOS |
Android |
| Механізм |
Silent Push (content-available) |
FCM Data Message |
| Фонове виконання |
Background Modes + 30с ліміт |
WorkManager + expedited |
| Force quit |
Не доставляється |
Доставляється (якщо не вбитий системою) |
| Doze Mode |
Throttling по квоті |
High priority обходить Doze |
| Badge оновлення |
UNUserNotificationCenter.setBadgeCount |
ShortcutBadger / лончер-специфічно |
Типові помилки та рішення
| Помилка |
Рішення |
| Silent push не доставляється на iOS після force quit |
Поясніть користувачеві, що додаток потрібно запускати вручну |
| FCM Data Message не пробуджує на Android 12+ |
Додайте setForegroundAsync() в expedited worker |
| Badge не оновлюється на Android Xiaomi |
Використовуйте ShortcutBadger з явною підтримкою Xiaomi |
| Перевищення квоти фонового виконання на iOS |
Зменшіть частоту silent push до 1 разу на 5-10 хвилин |
Що входить у налаштування silent push під ключ
При замовленні нашої послуги ви отримуєте:
- Проектування архітектури push-інфраструктури (APNs + FCM)
- Реалізацію обробників на iOS та Android з урахуванням граничних випадків
- Конфігурацію Background Modes, WorkManager, high-priority топіків
- Інтеграцію оновлення badge counter на обох платформах
- Документацію та навчання вашої команди
- Підтримку після запуску (1 місяць)
Чому варто довірити налаштування нам?
Ми спеціалізуємося на мобільній розробці з 10+ річним досвідом. За цей час реалізували понад 50 проєктів з push-інфраструктурою, включаючи високонавантажені додатки з мільйонами користувачів. Наші рішення проходять App Store Review та Google Play Console без зауважень. Використовуємо актуальні версії Swift, Kotlin, Flutter — стек підбирається під ваш проєкт.
Строки та вартість
Налаштування silent push для однієї платформи (iOS або Android) займає 3–5 робочих днів. Комплексне рішення для обох платформ — від 5 до 9 днів. Вартість розраховується індивідуально залежно від складності інтеграції та необхідного стеку. Оцінимо ваш проєкт безкоштовно — просто зв'яжіться з нами.
Отримайте консультацію — пишіть на пошту або через форму на сайті. Допоможемо налаштувати silent push так, щоб дані оновлювалися навіть у найжорсткіших умовах.
Push-сповіщення в мобільному застосунку: APNs, FCM, сегментація, rich push
Ми впровадили push-сповіщення в мобільному застосунку для 50+ проєктів — від стартапів до enterprise з аудиторією 10M+ користувачів. Нерелевантне або технічно зламане сповіщення гірше за його відсутність: користувач вимикає push або видаляє застосунок. Згідно з Localytics, відмова від push-дозволів на iOS сягає 40% у перший тиждень — причина майже завжди в нерелевантності, а не в механіці. Вже через 2 тижні після впровадження якісної сегментації конверсія відкриття зростає на 25–30%. Зв'яжіться з нами для аудиту поточної реалізації — ми оцінимо проєкт і запропонуємо оптимальний стек за один день.
Як працює інфраструктура: APNs та FCM
APNs — єдиний канал доставки на iOS. Все інше (OneSignal, Braze, Airship) — обгортки поверх нього. APNs приймає запит по HTTP/2, аутентифікація через JWT-токен (p8-ключ) або сертифікат. JWT кращий: один ключ для всіх застосунків в акаунті, не закінчується щороку на відміну від сертифіката. (Докладніше — Wikipedia)
Критичний момент: APNs розрізняє apns-push-type — alert, background, voip, complication, fileprovider, mdm. Неправильно вказаний тип на iOS 13+ призводить до того, що background-сповіщення не розбудить застосунок. Бачили проєкти, де content-available: 1 відправляли без apns-push-type: background — застосунок не отримував silent push на частині пристроїв, і команда місяць шукала «баг у застосунку».
FCM на Android працює через Google Play Services. Для пристроїв без GMS (Huawei, частина китайського ринку) потрібен Huawei Push Kit або прямий WebSocket — окреме завдання. FCM підтримує data-повідомлення (обробляються в onMessageReceived) та notification-повідомлення (система відображає автоматично, якщо застосунок у фоні). Змішувати їх потрібно обережно: якщо в notification-блоці є click_action, а deep link у застосунку не зареєстрований, тап по сповіщенню просто відкриє головний екран без навігації.
| Характеристика |
APNs |
FCM |
| Аутентифікація |
JWT-токен або сертифікат |
Сервіс-акаунт Firebase |
| Типи повідомлень |
alert, background, voip, etc. |
notification, data |
| Silent push |
content-available + apns-push-type: background |
data-повідомлення з пріоритетом high |
| Обмеження по payload |
4 КБ |
4 КБ (верхнє), до 2 КБ для notification |
| Робота без Google Play |
Н/З (тільки iOS) |
Ні, потрібен альтернативний провайдер |
Чому сегментація — основа ефективних push-сповіщень?
Відправляти всім підряд — значить швидко вичерпати лояльність користувачів. Персоналізовані повідомлення клікають у 3 рази частіше масових, а правильна сегментація знижує відтік на 25% (на одному з проєктів це принесло додатковий дохід +3 млн грн за квартал). Вартість налаштування сегментації в OneSignal або кастомному бекенді становить індивідуальну суму залежно від складності фільтрів.
Нормальна сегментація будується на кількох рівнях.
| Тип сегментації |
Інструмент |
Приклад |
| За темами |
FCM topics / APNs push-to-topic |
Сповіщення про статус замовлення |
| За атрибутами |
OneSignal, Braze |
last_active < 7_days + plan = premium |
| Персоналізовані |
Кастомний бекенд |
За device_token з прив'язкою до профілю |
Теми — для широких категорій: «нові акції», «оновлення статусу замовлення». Користувач підписується через FirebaseMessaging.getInstance().subscribeToTopic("orders"). Просто, але нема гнучкої фільтрації.
Сегменти за атрибутами — через OneSignal, Braze або кастомний бекенд. Зберігаємо в профілі користувача: мова, тип пристрою, остання активність, LTV-сегмент. Сповіщення йде тільки тим, у кого last_active < 7_days та plan = premium. OneSignal дозволяє будувати такі фільтри в інтерфейсі без коду.
Персоналізовані — за конкретним device_token. Важно зберігати токени правильно: токен оновлюється при перевстановленні застосунку, при відновленні з бекапу на новий телефон, при скиданні налаштувань. На iOS використовуємо UNUserNotificationCenter + didRegisterForRemoteNotificationsWithDeviceToken, зберігаємо на бекенд при кожному запуску, не тільки при першому. Інакше через 3 місяці 30% токенів у базі застарілі.
Що таке rich push і як він підвищує конверсію?
Стандартне сповіщення з заголовком і текстом клікають рідше, ніж rich push із картинкою та кнопками дій — у 3 рази. Але реалізація rich push — окрема робота на кожній платформі.
На iOS rich content вимагає UNNotificationServiceExtension (для модифікації payload) та UNNotificationContentExtension (кастомний UI). Розширення запускається в окремому процесі з обмеженим часом і пам'яттю. Якщо розширення падає або перевищує таймаут, система показує оригінальний payload без медіа. Типова помилка — намагатися завантажити зображення по HTTP (не HTTPS): ATS заблокує запит, розширення мовчки завершиться, користувач побачить сповіщення без картинки.
На Android з API 26+ сповіщення прив'язані до NotificationChannel. Якщо канал створений з IMPORTANCE_LOW, звук і вібрація недоступні. Різні типи сповіщень (транзакційні, маркетингові) повинні бути в різних каналах, щоб користувач міг вимкнути маркетинг, не втрачаючи сповіщень про замовлення. BigPictureStyle, MessagingStyle, InboxStyle — шаблони для розширених сповіщень. MessagingStyle з Person та аватарками — найкращий вибір для чатів.
| Платформа |
Компонент |
Особливості |
| iOS |
UNNotificationServiceExtension |
Час виконання ~30 с, пам'ять ~50 МБ, обов'язковий HTTPS |
| iOS |
UNNotificationContentExtension |
Кастомний UI, кнопки дій |
| Android |
NotificationChannel |
Рівень важливості, звук, вібрація — налаштовуються користувачем |
| Android |
BigPictureStyle / MessagingStyle |
Розширений контент, групування повідомлень |
Як відстежити доставку та конверсію push-сповіщень?
Відправити сповіщення — половина справи. Важно знати: доставлено воно, відкрито, чи привело до цільової дії.
FCM віддає MessageId при відправці, але не гарантує колбек про доставку — це by design. Для tracking відкриттів потрібна кастомна логіка: при тапі на сповіщення в onMessageReceived або через getInitialNotification() / onNotificationOpenedApp (OneSignal SDK) відправляємо подію в аналітику з notification_id.
OneSignal надає вбудовану аналітику доставки та CTR. Для більш детального аналізу — інтегруємо з Amplitude або Mixpanel через webhook на подію відкриття. Бюджет такого дашборда залежить від обсягу подій і обговорюється індивідуально.
Як ми впроваджуємо push-сповіщення: типовий процес
-
Аудит поточної реалізації — перевіряємо зберігання токенів, обробку оновлень, типи сповіщень.
-
Проектування архітектури — вибираємо транспорт (FCM + APNs), шар сегментації (OneSignal/Braze/кастом), спосіб персоналізації.
-
Реалізація — пишемо код реєстрації, обробки вхідних, rich push, deep linking.
-
Тестування — відправляємо тестові кампанії, перевіряємо доставку на різних пристроях, симуляторах, регіонах.
-
Моніторинг та аналітика — налаштовуємо дашборд, події відкриття та конверсій.
-
Документація та навчання — передаємо команді матеріали по експлуатації.
Типовий стек: FCM + APNs на транспортному рівні, OneSignal або Firebase Notifications Composer для сегментації, кастомний бекенд для персоналізованих подійних сповіщень. Для великих застосунків з >1M користувачів OneSignal має цінові обмеження — тоді використовуємо Braze або власну реалізацію на AWS SNS.
Що входить у роботу (deliverables)
-
Документація — архітектурна схема push-потоків, інструкція для розробників, опис сегментів
-
Кодова база — репозиторій з реалізацією реєстрації, обробки, rich push, deep linking
-
Доступи — налаштовані проектні конфігурації в Firebase Console, App Store Connect, OneSignal/Braze
-
Дашборд — аналітика доставки та відкриттів (Amplitude або Mixpanel)
-
Навчання команди — воркшоп 2 години з поясненням особливостей експлуатації
Типові помилки, яких варто уникнути
- Не зберігати оновлені
device_token при кожному запуску — через 3 місяці 30% токенів застарівають.
- Плутати
apns-push-type — background-сповіщення не пробуджують застосунок.
- Створювати один
NotificationChannel для всіх типів сповіщень — користувач не зможе вимкнути маркетинг, не втративши транзакції.
- Завантажувати медіа в rich push по HTTP — ATS блокує запит на iOS.
- Не перевіряти deep link у таргетингу — переходи йдуть на головний екран.
Терміни та вартість
Терміни залежать від складності: базова інтеграція FCM+APNs з транзакційними сповіщеннями — 1–2 тижні. Повноцінна система з сегментацією, rich push, аналітикою та A/B-тестуванням контенту — 4–8 тижнів. Вартість розраховується індивідуально після аудиту.
Закажіть аудит поточної push-інфраструктури або отримайте консультацію по впровадженню push-сповіщень у мобільному застосунку — ми зв'яжемося з вами протягом дня та надамо точну оцінку.