Notification Extension — это механизм iOS, который позволяет модифицировать содержимое и внешний вид push-уведомлений до их отображения пользователю. Расширения работают на стороне операционной системы в отдельном процессе: UNNotificationServiceExtension обрабатывает входящий контент, а UNNotificationContentExtension управляет интерфейсом. По данным Apple Developer Documentation, 2026, Service Extension получает до 30 секунд на выполнение задач перед показом уведомления. Это ограничение критично при загрузке вложений или расшифровке данных.
Главное
Notification Extension — это программный компонент iOS, который расширяет стандартное поведение push-уведомлений, добавляя возможность модификации контента и кастомизации интерфейса. В отличие от обычных уведомлений, которые отображаются системой в стандартном виде, расширения позволяют разработчику влиять на содержимое до показа и создавать уникальный пользовательский интерфейс.
Apple предоставляет два типа Notification Extension для разных целей: UNNotificationServiceExtension отвечает за обработку входящего пейлоуда, а UNNotificationContentExtension управляет отображением. Service Extension запускается до показа уведомления и получает ограниченное время на выполнение — до 30 секунд по данным Apple Developer Documentation. Content Extension активируется после того, как пользователь взаимодействует с уведомлением, и отображает кастомный view.
Стандартное push-уведомление iOS отображается системой автоматически на основе полей alert, title и subtitle из JSON-пейлоуда. Notification Extension перехватывает управление: Service Extension получает сырой пейлоуд, модифицирует его и передаёт системе для показа. Content Extension заменяет стандартный баннер на произвольный интерфейс с любыми элементами управления.
Когда устройство получает push-уведомление с ключом mutable-content: 1, система запускает Service Extension в отдельном процессе. Процесс расширения изолирован от основного приложения и имеет собственную песочницу с лимитом памяти 50 MB. После завершения обработки расширение вызывает completion handler, передавая модифицированный UNNotificationContent системе для отображения.
UNNotificationServiceExtension — это основной инструмент для программного изменения push-уведомлений до их показа пользователю. Расширение активируется автоматически при получении уведомления, в пейлоуде которого установлен флаг mutable-content: 1. В течение 30 секунд расширение может загрузить медиа-вложение, изменить текст, расшифровать зашифрованные данные или обогатить контент.
Расширение реализует два ключевых метода из протокола UNNotificationServiceExtension. Метод didReceive получает входящий запрос с сырым UNNotificationRequest и позволяет модифицировать его через completion handler с новым UNNotificationContent. Метод serviceExtensionTimeWillExpire вызывается системой за секунду до истечения тайм-аута — в нём необходимо завершить обработку и передать текущий (возможно, частичный) результат.
Рассмотрим сценарий, когда сервер отправляет push с URL изображения в кастомном поле. Service Extension загружает это изображение по сети, создаёт UNNotificationAttachment и добавляет его в контент. UNNotificationAttachment принимает локальный файл изображения, видео или аудио и автоматически копирует его в sandbox расширения. После создания attachment расширение передаёт обновлённый контент системе.
class NotificationService: UNNotificationServiceExtension {
override func didReceive(_ request: UNNotificationRequest,
withContentHandler contentHandler:
@escaping (UNNotificationContent) -> Void) {
let userInfo = request.content.userInfo
guard let imageURL = URL(string: userInfo["image-url"] as! String)
else { contentHandler(request.content); return }
let attachment = try! UNNotificationAttachment(
identifier: "image", url: imageURL,
options: [UNNotificationAttachmentOptionsTypeHintKey: "jpg"])
let modifiedContent = request.content.mutableCopy()
as! UNMutableNotificationContent
modifiedContent.attachments = [attachment]
contentHandler(modifiedContent)
}
override func serviceExtensionTimeWillExpire() {
contentHandler?(bestAttemptContent ?? request.content)
}
}
При частой отправке уведомлений с одинаковыми вложениями рекомендуется кэшировать загруженные файлы на устройстве. FileManager предоставляет доступ к директории кэша расширения, которая сохраняется между запусками. Это уменьшает время обработки последующих уведомлений и снижает нагрузку на сеть. По данным Apple, кэширование вложений может сократить время обработки до 2–5 секунд вместо полной загрузки.
UNNotificationContentExtension позволяет заменить стандартный баннер уведомления на произвольный интерфейс, созданный в Interface Builder или SwiftUI. Расширение активируется, когда пользователь совершает действие с уведомлением: нажатие, смахивание вниз или 3D Touch. Content Extension получает контент, уже обработанный Service Extension, и отображает его в кастомном представлении.
Каждый Content Extension привязывается к одной или нескольким категориям уведомлений через Info.plist. Категория определяется на сервере полем category в пейлоуде APNS. Система автоматически выбирает нужный extension на основе категории полученного уведомления. Интерфейс строится через storyboard с использованием стандартных UIKit-компонентов или SwiftUI View.
Content Extension поддерживает кастомные кнопки и обработчики нажатий, определённые в UNNotificationAction. UNNotificationAction создаётся на этапе регистрации категории и может быть текстовым вводом через UNTextInputNotificationAction. Когда пользователь нажимает кнопку, расширение получает callback didReceive с идентификатором действия и может выполнить соответствующую логику — открыть URL, отправить запрос на сервер или обновить интерфейс.
Content Extension работает в изолированном процессе с собственным циклом выполнения и лимитом памяти около 50 MB. Производительность расширения критична, поскольку системный watchdog завершает процесс при превышении лимитов. Рекомендуется избегать тяжёлых вычислений, загрузки больших изображений и длительных сетевых запросов внутри Content Extension.
UNNotificationAttachment — это объект, который добавляет медиа-файл к push-уведомлению: изображение, видео, аудио или GIF. Вложение создаётся из локального URL файла, который обязательно должен находиться в песочнице расширения. Максимальный размер вложения не должен превышать 10 MB, иначе система отклонит attachment при создании.
Apple поддерживает ограниченный набор форматов для медиа-вложений. Изображения — JPEG, PNG, GIF (включая анимированные), TIFF. Видео — MPEG, MP4, MOV с максимальной длительностью 30 секунд. Аудио — MP3, AAC, WAV, CAF. Для каждого формата можно указать тип через UNNotificationAttachmentOptionsTypeHintKey, что помогает системе корректно обработать файл.
Поскольку push-пейлоуд содержит только URL, а не сам файл, загрузку вложения нужно выполнять внутри Service Extension. Максимальное время загрузки ограничено 30 секундами, поэтому рекомендуется использовать URLSession с минимальными настройками и отключать загрузку при слабом сигнале. Если вложение не загрузилось вовремя, уведомление показывается без медиа — это поведение системы по умолчанию.
Рассмотрим полный пример Notification Extension, который загружает изображение, скачивает его и добавляет к уведомлению. NotificationService наследуется от UNNotificationServiceExtension и переопределяет метод didReceive. В примере показана обработка опциональных полей, создание attachment и вызов completion handler с модифицированным контентом.
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler:
@escaping (UNNotificationContent) -> Void
) {
self.contentHandler = contentHandler
self.bestAttemptContent =
(request.content.mutableCopy()
as! UNMutableNotificationContent)
guard let attachmentURLString =
bestAttemptContent?.userInfo["attachment-url"] as? String,
let url = URL(string: attachmentURLString)
else {
contentHandler(request.content)
return
}
URLSession.shared.downloadTask(with: url) {
[weak self] localURL, _, error in
guard let localURL = localURL, error == nil
else {
contentHandler(request.content)
return
}
let attachment = try! UNNotificationAttachment(
identifier: "media", url: localURL)
self?.bestAttemptContent?.attachments = [attachment]
contentHandler(self?.bestAttemptContent
?? request.content)
}.resume()
}
override func serviceExtensionTimeWillExpire() {
if let content = bestAttemptContent {
contentHandler?(content)
}
}
}
Для корректной работы расширения необходимо зарегистрировать категории уведомлений в Info.plist. Ключ NSExtensionPointIdentifier устанавливается в com.apple.usernotifications.service для Service Extension или com.apple.usernotifications.content для Content Extension. Категории определяются в AppDelegate при запуске приложения через UNUserNotificationCenter, и расширение активируется только для уведомлений с соответствующей категорией в пейлоуде.
Часто задаваемые вопросы
Service Extension модифицирует контент до показа уведомления — добавляет медиа, меняет текст, расшифровывает данные. Content Extension заменяет интерфейс уведомления на кастомный после взаимодействия пользователя. Service Extension работает до показа, Content Extension — после.
Система выделяет 30 секунд на выполнение кода в didReceive. Если обработка не завершена за это время, вызывается serviceExtensionTimeWillExpire, где нужно передать текущий результат. Рекомендуется укладываться в 10–15 секунд с учётом загрузки вложений.
Да, SwiftUI поддерживается в Content Extension начиная с iOS 16. View оборачивается в UIHostingController и добавляется на storyboard. Однако из-за лимитов памяти рекомендуется использовать SwiftUI только для простых интерфейсов с минимальным количеством элементов.
При ошибке загрузки или превышении лимита времени просто вызовите completion handler с исходным контентом без attachment. Система покажет уведомление в стандартном виде без медиа. Логируйте ошибки через OSLog для диагностики, но не блокируйте показ уведомления.
Расширение работает в изолированном процессе с лимитом около 50 MB. При превышении система убивает процесс через watchdog. Избегайте загрузки больших файлов, хранения изображений в памяти и утечек при работе с URLSession.
Итоги
Мы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также