Notification Service Extension: что это, обработка контента до показа на iOS

Автор: IT Sectr Опубликовано: 2026-03-21 Время чтения: 8 мин

Notification Service Extension — это расширение iOS, которое перехватывает push-уведомление до его отображения пользователю и позволяет модифицировать контент. Расширение может расшифровать зашифрованные данные, скачать медиавложения, изменить текст или добавить кастомные поля. По данным Apple Developer, 2025, Notification Service Extension имеет до 30 секунд на выполнение задачи в фоновом режиме.

Главное

  • Notification Service Extension — iOS-расширение для обработки push-уведомления до показа.
  • Расширение наследуется от UNNotificationServiceExtension и реализует метод didReceive.
  • Доступно до 30 секунд фонового выполнения для скачивания и обработки данных.
  • Основные сценарии: расшифровка payload, загрузка изображений и видео, валидация контента.
  • Расширение может отложить показ уведомления или полностью отменить его через contentHandler.

Что такое Notification Service Extension

Notification Service Extension — это app extension в iOS, которое запускается перед отображением push-уведомления. Оно позволяет серверу отправлять минимальный payload, а расширение — дополнять его контентом: скачивать изображения, расшифровывать данные, заменять текст. Пользователь видит уже готовое, обработанное уведомление.

Как это работает

Когда iOS получает push-уведомление, система проверяет наличие расширения для данного приложения. Если расширение зарегистрировано, iOS запускает его в фоновом процессе и передаёт содержимое уведомления через метод didReceive(_:withContentHandler:). Расширение обрабатывает контент и вызывает contentHandler с модифицированным содержимым. Если расширение не успевает за 30 секунд, система отображает исходное уведомление.

Когда нужно использовать Service Extension

Service Extension необходим в сценариях, где контент уведомления требует обработки на устройстве. Безопасные коммуникации: сервер отправляет зашифрованный payload, расширение расшифровывает его локально. Богатые медиауведомления: сервер отправляет URL изображения, расширение скачивает и прикрепляет его. Динамическая локализация: расширение подставляет текст на языке устройства.

СценарийБез расширенияС расширением
ИзображениеНе поддерживаетсяСкачивается и отображается
ШифрованиеСервер хранит ключРасшифровка на устройстве
ТекстЖёстко задан на сервереДинамическая подстановка
ВалидацияНе проверяетсяОтмена вредоносных уведомлений

Ограничения и время выполнения

Notification Service Extension работает в ограниченном окружении. Максимальное время выполнения — 30 секунд. Расширение не имеет доступа к основному хранилищу приложения (кроме App Group). Размер расширения ограничен 50 МБ. При превышении времени система вызывает contentHandler с исходным контентом, и все изменения теряются.

Создание расширения и настройка Info.plist

В Xcode Notification Service Extension добавляется через создание нового target типа Notification Service Extension. Xcode генерирует шаблон класса NotificationService, наследующий от UNNotificationServiceExtension, с двумя методами: didReceive и serviceExtensionTimeWillExpire.

Добавление target в проект

В Xcode выберите File → New → Target → Notification Service Extension. Укажите имя (например, PushNotificationService) и язык Swift. Убедитесь, что target добавлен в основное приложение и имеет правильную подпись. После создания будет сгенерирован класс NotificationService.swift с базовой реализацией.

Структура Info.plist расширения

Info.plist расширения содержит ключ NSExtension с подключами NSExtensionPointIdentifier (com.apple.usernotifications.service) и NSExtensionPrincipalClass (имя вашего контроллера). Дополнительно можно указать NSExtensionAttributes с правилами активации расширения. Эти настройки Xcode генерирует автоматически.

Пример базового расширения

Базовая реализация переопределяет didReceive, модифицирует контент уведомления и вызывает contentHandler. Если обработка занимает слишком много времени, вызывается serviceExtensionTimeWillExpire, где необходимо завершить работу с текущим состоянием.

swift
import UserNotifications

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(
        request: UNNotificationRequest,
        withContentHandler handler: @escaping (UNNotificationContent) -> Void
    ) {
        contentHandler = handler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        if let bestAttemptContent = bestAttemptContent {
            bestAttemptContent.title = "[Обработано] \(bestAttemptContent.title)"
            contentHandler?(bestAttemptContent)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler,
           let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}

Расшифровка зашифрованного payload

Одним из ключевых применений Service Extension является расшифровка содержимого уведомления на устройстве. Сервер отправляет зашифрованный payload, а расширение расшифровывает его, используя ключ, хранящийся в Keychain или App Group. Это гарантирует, что контент недоступен для перехвата при передаче.

Архитектура безопасной доставки

Сервер шифрует тело уведомления с использованием симметричного ключа (AES-256). Ключ шифрования предварительно согласовывается между клиентом и сервером. Расширение получает зашифрованную строку в поле data payload, расшифровывает её и подставляет в поля уведомления. Пользовательский ключ может быть получен из Keychain после аутентификации.

swift
override func didReceive(
    request: UNNotificationRequest,
    withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
    guard let content = request.content.mutableCopy()
        as? UNMutableNotificationContent else {
        handler(request.content)
        return
    }

    guard let encryptedData = content.userInfo["encrypted_data"]
        as? String else {
        handler(content)
        return
    }

    let decrypted = CryptoService.decrypt(encryptedData)
    content.body = decrypted.body
    content.title = decrypted.title
    handler(content)
}

Безопасное хранение ключей

Ключ для расшифровки не должен храниться в коде расширения или NSUserDefaults. Используйте iOS Keychain с доступом через App Group, чтобы и приложение, и расширение могли читать ключ. Для генерации ключа на клиенте используйте Security.framework с алгоритмом AES-256-GCM.

Скачивание и прикрепление медиавложений

Самое частое применение Notification Service Extension — скачивание изображений, GIF и видео для последующего отображения в уведомлении. Сервер отправляет URL медиафайла, а расширение скачивает его, сохраняет во временную директорию и создаёт UNNotificationAttachment.

Процесс загрузки и прикрепления медиа

Расширение получает URL изображения из поля payload уведомления. Используя URLSession, расширение скачивает файл во временную директорию. После завершения загрузки создаётся UNNotificationAttachment с локальным URL. Вложение передаётся в модифицированный контент. iOS автоматически отображает изображение в стандартном интерфейсе или в Notification Content Extension.

swift
private func downloadAndAttachMedia(
    content: UNMutableNotificationContent,
    mediaUrl: String,
    handler: @escaping (UNNotificationContent) -> Void
) {
    guard let url = URL(string: mediaUrl) else {
        handler(content)
        return
    }

    let task = URLSession.shared.downloadTask(with: url) { localUrl, _, error in
        guard let localUrl = localUrl, error == nil else {
            handler(content)
            return
        }

        let attachment = try? UNNotificationAttachment(
            identifier: "media",
            url: localUrl,
            options: nil
        )

        if let attachment = attachment {
            content.attachments = [attachment]
        }
        handler(content)
    }
    task.resume()
}

Поддерживаемые форматы медиа

iOS поддерживает следующие форматы для отображения в уведомлениях: JPEG, PNG, GIF (статичные), MPEG-4 видео до 50 МБ. Для аудиофайлов поддерживается MP3, AAC и ALAC. Важно: все медиафайлы должны быть скачаны в течение 30-секундного лимита. Для больших файлов рекомендуется использовать серверную обрезку или прогрессивную загрузку.

Управление временем и fallback-сценарии

Управление 30-секундным лимитом — ключевая задача при разработке Notification Service Extension. Если расширение не успевает завершить обработку, система вызывает serviceExtensionTimeWillExpire и отображает исходный контент. Необходимо предусмотреть fallback-сценарии для каждого типа обработки.

Стратегия приоритетов

Разделите задачи по приоритетам. Критичные модификации (расшифровка, базовая локализация) выполняйте в первую очередь. Опциональные улучшения (скачивание изображений, обогащение текста) — во вторую очередь. Используйте URLSession с таймаутами для сетевых запросов, чтобы не тратить весь лимит на одну операцию.

Fallback при ошибках

Если скачивание изображения не удалось или расшифровка payload вернула ошибку, расширение должно вызвать contentHandler с исходным контентом. Никогда не завершайте расширение без вызова contentHandler — это приводит к потере уведомления. Безопасный fallback всегда должен быть предусмотрен в коде расширения.

swift
override func didReceive(
    request: UNNotificationRequest,
    withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
    let content = (request.content.mutableCopy()
        as? UNMutableNotificationContent) ?? request.content

    // Критичная задача: расшифровка
    var decryptedContent = tryDecryptPayload(content)

    // Опциональная задача: медиа
    guard let mediaUrl = decryptedContent.userInfo["media_url"]
        as? String else {
        handler(decryptedContent)
        return
    }

    downloadAndAttachMedia(
        content: decryptedContent,
        mediaUrl: mediaUrl,
        handler: handler
    )
}

Тестирование расширения

Для тестирования Notification Service Extension используйте Xcode: выберите target расширения, запустите на симуляторе и отправьте push-уведомление через терминал или Firebase Console. Логируйте каждый этап обработки через os_log — это помогает диагностировать проблемы с таймингами и ошибками загрузки.

Часто задаваемые вопросы

Что произойдёт, если расширение не уложится в 30 секунд?

Система вызовет serviceExtensionTimeWillExpire, после чего отобразит исходное уведомление без изменений. Все скачанные файлы и модификации будут отброшены.

Можно ли отменить показ уведомления из расширения?

Да, если вызвать contentHandler с пустым контентом (UNNotificationContent с пустыми полями), уведомление не будет показано. Это используется для фильтрации спам-уведомлений или некорректных данных.

Как передать токен авторизации для скачивания медиа?

Токен можно передать в userInfo payload уведомления или получить из Keychain через App Group. Не рекомендуется хранить токены в UserDefaults расширения.

Требуется ли специальная настройка сертификатов для расширения?

Расширение должно быть подписано тем же сертификатом разработчика, что и основное приложение. Для продакшена требуется production-сертификат с включённым capability Push Notifications.

Как отладить расширение на реальном устройстве?

Подключите устройство к Xcode, выберите target расширения в схеме запуска и отправьте push-уведомление через Firebase Console. Breakpoints в расширении работают так же, как в основном приложении.

Итоги

  • Notification Service Extension — iOS-расширение для фоновой обработки push-уведомлений до показа.
  • Максимальное время выполнения — 30 секунд, после чего система отображает исходный контент.
  • Основные применения: расшифровка payload, скачивание медиа, валидация и локализация контента.
  • Расширение наследуется от UNNotificationServiceExtension с методами didReceive и serviceExtensionTimeWillExpire.
  • Для скачивания медиа используйте URLSession, для хранения ключей — iOS Keychain.
  • Всегда предусматривайте fallback — вызывайте contentHandler с исходным контентом при ошибках.
  • Комбинируйте Service Extension с Content Extension для полного контроля над уведомлениями.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также