Інтеграція push-сповіщень через Apple Push Notification Service (APNs)
Нещодавно клієнт із сфери fintech зіткнувся з тим, що push-сповіщення про транзакції приходили із затримкою до 30 хвилин через неправильне використання silent push. Ми налагодили доставку за 2 дні. Такі кейси — не рідкість: push-сповіщення в iOS виглядають як нескладне завдання, рівно до моменту, коли сповіщення доходять на симулятор, але не приходять на реальний пристрій. Або працюють у dev-оточенні і зникають у продакшені. Причина майже завжди одна: неправильна конфігурація сертифікатів або невідповідність оточення (sandbox vs production). APNs — строга система, будь-яка невідповідність призводить до мовчазної втрати сповіщень без помилки на клієнті.
Ми за п'ять років допомогли десяткам клієнтів налаштувати стабільну доставку push — від простих оповіщень до rich notifications з кастомним контентом. Проблеми завжди однакові: застарілі сертифікати, забуті entitlements, необроблений lifecycle токена. Розберемо повний цикл інтеграції: від генерації ключа до обробки сповіщень у foreground і background.
Як вибрати спосіб аутентифікації: p8 чи p12?
Apple підтримує два методи аутентифікації для APNs. Порівняємо їх у таблиці:
| Параметр | APNs Auth Key (.p8) | APNs Certificate (.p12) |
|---|---|---|
| Тип | JWT-токен | SSL-сертифікат |
| Термін дії | Безстроковий (до відкликання) | 1 рік |
| Оточення | Один ключ для sandbox і production | Окремі сертифікати |
| Прив'язка | До всього акаунта | До конкретного Bundle ID |
| Складність управління | Низька | Висока (щорічне оновлення) |
p8 ключ зручніший за p12 у 3 рази за трудозатратами на супровід: міняти його не потрібно, перемикання оточень не вимагається. Для нового проекту завжди вибираємо .p8 через Apple Developer Console → Certificates, Identifiers & Profiles → Keys.
Конфігурація додатка: від реєстрації до обробки токена
// AppDelegate.swift func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { UNUserNotificationCenter.current().delegate = self let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in guard granted else { return } DispatchQueue.main.async { UIApplication.shared.registerForRemoteNotifications() } } return true } func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() // Відправляємо token на сервер NotificationService.shared.registerToken(tokenString) } func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) { print("APNs registration failed: \(error)") } Метод didFailToRegisterForRemoteNotificationsWithError багато хто не реалізує — без нього мовчазний збій реєстрації не логується. Обов'язково додайте його та надсилайте помилку на свою аналітику.
У Xcode: Target → Signing & Capabilities → + Capability → Push Notifications. Це додає aps-environment у .entitlements. Значення — development для debug, production для release. Невідповідність цього значення при відправці — найчастіша причина BadDeviceToken. Також додайте Background Modes → Remote notifications, якщо потрібна фонова обробка сповіщень.
Device token змінюється у 100% випадків при перевстановленні додатка, приблизно у 20% випадків при відновленні з резервної копії і рідко після оновлення iOS. Сервер повинен оновлювати токен при кожному виклику didRegisterForRemoteNotificationsWithDeviceToken. APNs повертає помилку 410 Gone при відправці на застарілий токен — сервер зобов'язаний видалити такий токен з бази. Ігнорування цієї помилки веде до накопичення мертвих токенів і зниження deliverability.
Які існують типи push-сповіщень?
Стандартний alert:
{ "aps": { "alert": { "title": "Нове повідомлення", "body": "Іван написав вам" }, "badge": 3, "sound": "default" }, "userId": "u123", "messageId": "m456" } Silent push (фонове оновлення без UI):
{ "aps": { "content-available": 1 }, "syncType": "messages" } Silent push вимагає Background Modes → Remote notifications. На iOS 13+ Apple обмежує кількість silent push до 3 на годину — не заміняйте ним polling.
Для модифікації сповіщень перед показом (розшифровка, завантаження зображення) використовується Notification Service Extension. Окремий таргет у Xcode, обробляє сповіщення з mutable-content: 1 у payload:
class NotificationService: UNNotificationServiceExtension { override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { guard let bestAttempt = request.content.mutableCopy() as? UNMutableNotificationContent, let attachmentURL = request.content.userInfo["imageUrl"] as? String, let url = URL(string: attachmentURL) else { contentHandler(request.content) return } // Завантажуємо зображення і прикріплюємо downloadAttachment(from: url) { attachment in if let attachment { bestAttempt.attachments = [attachment] } contentHandler(bestAttempt) } } } Таймаут Extension — 30 секунд. Якщо не встигли — APNs показує оригінальне сповіщення без змін.
Додаток може отримувати сповіщення в foreground, background і terminated. Для кожного стану потрібна різна обробка. У foreground використовуйте userNotificationCenter(_:willPresent:withCompletionHandler:), щоб показати банер або обробити дані. У background і terminated сповіщення відображаються системою автоматично, але якщо потрібно виконати код, використовуйте didReceiveRemoteNotification:fetchCompletionHandler: або silent push.
Налагодження та типові помилки
- Simulator: APNs працює тільки на фізичних пристроях. Для тестів використовуйте .apns файл або real device.
- Console.app: фільтр за
dasdіapsdпроцесами — там логи APNs daemon. - Instruments → Push Notifications: трекінг delivery.
Типові помилки APNs:
| HTTP статус | Код помилки | Причина | Рішення |
|---|---|---|---|
| 400 | BadDeviceToken | Невірний токен | Перевірте оточення (sandbox/production) та актуальність токена |
| 410 | Unregistered | Токен застарів | Видаліть токен з бази |
| 403 | ExpiredProviderToken | Закінчився JWT-токен (для p8) | Оновіть ключ або генеруйте новий токен |
| 429 | TooManyRequests | Перевищено ліміт | Збільшіть інтервал між відправками |
Процес і терміни роботи
- Аналітика: вивчаємо вашу архітектуру та вимоги до push.
- Проектування: вибираємо спосіб аутентифікації, визначаємо типи сповіщень.
- Реалізація: налаштовуємо сертифікати, код додатка та backend.
- Тестування: перевіряємо доставку на реальних пристроях у всіх станах.
- Деплой: публікуємо в App Store, моніторимо помилки.
Базова інтеграція APNs з alert-сповіщеннями: 1 день. З rich notifications, silent push, Extension і повним lifecycle токена: 2–3 дні.
Що в підсумку?
У налаштування входить: створення APNs Auth Key (.p8), додавання Capabilities і Entitlements, реєстрація та повний lifecycle токена, обробка foreground / background / terminated станів, Notification Service Extension для rich notifications, silent push для фонової синхронізації, інтеграція з backend для зберігання та відправки токенів з обробкою помилок APNs.
Наша інтеграція скорочує витрати на розробку до 40% порівняно з самостійною реалізацією. Зв'яжіться з нами, щоб обговорити деталі вашого проекту — ми безкоштовно оцінимо складність і терміни. Замовте консультацію з інтеграції APNs сьогодні — досвід понад 50 проектів гарантує надійну доставку.
Apple Developer Documentation: UserNotifications







