Пользователи жалуются, что push-уведомление приходит без картинки — сервер её отправил, но на устройстве пусто. Или в e2e-мессенджере отображается «Новое сообщение» вместо текста из-за шифрования. Стандартной обработки push недостаточно. Решение — Notification Service Extension. Мы создаём этот Extension под ключ: от настройки таргета до тестирования на реальных устройствах.
Какие проблемы решает Notification Service Extension?
Media attachments. Сервер отправляет URL изображения, а Extension скачивает его через URLSession, сохраняет во временную директорию, создаёт UNNotificationAttachment и передаёт через contentHandler. Без этого attachments в push не работают — пользователь видит только текст. Время загрузки ограничено 30 секундами, поэтому мы настраиваем таймаут URLSession на 20 секунд с fallback: если не успели — показываем уведомление без картинки, не фейлим Extension.
Сквозное шифрование. Payload приходит зашифрованным, Extension расшифровывает его с ключом из Keychain и подставляет читаемый текст. В e2e-мессенджерах это единственный способ показать содержимое уведомления, не раскрывая ключи на сервере. Для шаринга ключей используем App Groups и Keychain Sharing с общим access group.
Аналитика доставки. Extension отправляет fire-and-forget запрос на backend при получении уведомления — фиксирует delivered-событие. UIApplicationDelegate.userNotificationCenter(_:didReceive:) срабатывает только при тапе, а Extension — сразу при доставке. Это даёт точные метрики.
Как реализовать сквозное шифрование в Notification Service Extension?
Процесс расшифровки состоит из нескольких шагов:
- Получить зашифрованный payload из
request.content.userInfo. - Извлечь ключ из общего Keychain (настроить Keychain Sharing с основным приложением).
- Выполнить расшифровку (например, AES-GCM) и сформировать читаемое тело уведомления.
- Передать изменённый контент через
contentHandler.
Этот подход безопаснее, чем расшифровка на сервере: ключ никогда не покидает устройство. Мы используем этот метод в мессенджерах с end-to-end шифрованием, где сервер не имеет доступа к содержимому сообщений.
Как мы реализуем Extension: разбор на примере медиавложения
Вот типовой код для обработки:
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { self.contentHandler = contentHandler bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) // скачиваем attachment, при ошибке — contentHandler(bestAttemptContent!) } override func serviceExtensionTimeWillExpire() { // вызывается за мгновение до таймаута — показываем что есть if let contentHandler, let content = bestAttemptContent { contentHandler(content) } } Extension живёт в отдельном процессе и не имеет прямого доступа к данным основного приложения. Для обмена используем App Groups: UserDefaults(suiteName: "group.com.example.app") и FileManager с контейнером группы. Keychain Sharing настраивается через kSecAttrAccessGroup с тем же group identifier.
Почему Extension не работает в симуляторе и что с этим делать
APNs-push не доставляются в симулятор. Для тестирования используйте реальное устройство или симулируйте локальные уведомления через Xcode. Мы гарантируем корректную работу на физических девайсах после настройки provisioning profile и entitlements.
Сравнение сценариев: таблица времени и сложности
| Сценарий | Время реализации | Сложность |
|---|---|---|
| Медиавложение | 1 день | Низкая |
| Расшифровка payload | 2 дня | Средняя |
| Аналитика доставки | 1 день | Низкая |
| Комбинированный (3+ логики) | 3–4 дня | Высокая |
Чек-лист типичных ошибок при настройке Notification Service Extension
Нажмите, чтобы развернуть список
- Забыли добавить capability App Groups в Extension таргет.
- Не настроили provisioning profile для Extension (отдельный App ID).
- Используете симулятор для тестирования push — уведомления не приходят.
- Не установили таймаут URLSession — Extension может упасть с ошибкой.
- Keychain Sharing не работает без общего access group с основным приложением.
Сравнение подходов: медиавложение через Notification Service Extension vs. серверная генерация
| Подход | Задержка доставки | Использование трафика | Гибкость |
|---|---|---|---|
| Extension скачивает медиа | 0.5–2 сек загрузки | Трафик только на устройстве | Любой размер и формат |
| Сервер генерирует push с медиа | Нет задержки | Двойной трафик (сервер→APNs→устройство) | Ограничен 10 MB |
Notification Service Extension лучше подходит, если нужно отображать большие изображения или видео — экономит до 40% трафика по сравнению с серверной генерацией.
Что входит в работу
- Создание и настройка таргета Notification Service Extension в Xcode
- Реализация логики: attachment, расшифровка или аналитика
- Настройка App Groups и Keychain Sharing для обмена данными
- Тестирование на реальном устройстве (Extension не работает в симуляторе для push от APNs)
- Подготовка entitlements и provisioning profiles для Extension таргета
Сроки и стоимость
Сроки: от 1 дня (один сценарий) до 3–4 дней (комплексное решение). Стоимость рассчитывается индивидуально — свяжитесь с нами для оценки вашего проекта. Закажите реализацию Extension и получите гарантию качества: наши инженеры имеют 5+ лет опыта в iOS-разработке и сертификацию Apple. Пишите — предложим оптимальное решение.
Apple Developer Documentation — UNNotificationServiceExtension содержит полную спецификацию API.







