Notification Extension е iOS механизъм, който позволява модифициране на съдържанието и външния вид на push известията преди показването им на потребителя. Разширенията работят от страна на операционната система в отделен процес: UNNotificationServiceExtension обработва входящото съдържание, а UNNotificationContentExtension управлява интерфейса. Според Apple Developer Documentation, 2026, Service Extension получава до 30 секунди за изпълнение на задачи преди показване на известието. Това ограничение е критично при зареждане на прикачени файлове или декриптиране на данни.
Основни моменти
Notification Extension е софтуерен компонент на iOS, който разширява стандартното поведение на push известията, добавяйки възможност за модифициране на съдържанието и персонализиране на интерфейса. За разлика от обикновените известия, които системата показва в стандартен вид, разширенията позволяват на разработчика да влияе върху съдържанието преди показване и да създава уникален потребителски интерфейс.
Apple предоставя два типа Notification Extension за различни цели: UNNotificationServiceExtension отговаря за обработка на входящия payload, а UNNotificationContentExtension управлява показването. Service Extension се стартира преди показване на известието и има ограничено време за изпълнение — до 30 секунди според Apple Developer Documentation. Content Extension се активира, след като потребителят взаимодейства с известието, и показва персонализиран изглед.
Стандартното iOS push известие се показва автоматично от системата на базата на полетата alert, title и subtitle от JSON-payload-а. Notification Extension поема контрола: Service Extension получава суровия payload, модифицира го и го предава на системата за показване. Content Extension заменя стандартния банер с произволен интерфейс с всякакви контролни елементи.
Когато устройството получи push известие с ключ mutable-content: 1, системата стартира Service Extension в отделен процес. Процесът на разширението е изолиран от основното приложение и има собствена пясъчна кутия с лимит на паметта от 50 MB. След приключване на обработката, разширението извиква completion handler, предавайки модифицирания UNNotificationContent на системата за показване.
UNNotificationServiceExtension е основният инструмент за програмна промяна на push известията преди показването им на потребителя. Разширението се активира автоматично при получаване на известие, в чийто payload е зададен флагът mutable-content: 1. В рамките на 30 секунди разширението може да зареди медиен прикачен файл, да промени текст, да декриптира криптирани данни или да обогати съдържанието.
Разширението имплементира два ключови метода от протокола UNNotificationServiceExtension. Методът didReceive получава входящата заявка със суров UNNotificationRequest и позволява нейната модификация чрез completion handler с нов UNNotificationContent. Методът serviceExtensionTimeWillExpire се извиква от системата секунда преди изтичане на времето — в него трябва да се завърши обработката и да се предаде текущият (евентуално частичен) резултат.
Нека разгледаме сценарий, при който сървърът изпраща push с URL на изображение в персонализирано поле. Service Extension зарежда това изображение по мрежата, създава UNNotificationAttachment и го добавя към съдържанието. UNNotificationAttachment приема локален файл с изображение, видео или аудио и автоматично го копира в пясъчната кутия на разширението. След създаване на прикачения файл, разширението предава актуализираното съдържание на системата.
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 payload-а. Системата автоматично избира подходящото разширение на базата на категорията на полученото известие. Интерфейсът се изгражда чрез 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, в противен случай системата ще отхвърли прикачения файл при създаване.
Apple поддържа ограничен набор от формати за медийни прикачени файлове. Изображения — JPEG, PNG, GIF (включително анимирани), TIFF. Видео — MPEG, MP4, MOV с максимална продължителност 30 секунди. Аудио — MP3, AAC, WAV, CAF. За всеки формат може да се посочи тип чрез UNNotificationAttachmentOptionsTypeHintKey, което помага на системата да обработи файла правилно.
Тъй като push payload-ът съдържа само URL, а не самия файл, зареждането на прикачения файл трябва да се извърши вътре в Service Extension. Максималното време за зареждане е ограничено до 30 секунди, поради което се препоръчва използването на URLSession с минимални настройки и изключване на зареждането при слаб сигнал. Ако прикаченият файл не се зареди навреме, известието се показва без медия — това е поведението по подразбиране на системата.
Нека разгледаме пълен пример за Notification Extension, който зарежда изображение, изтегля го и го добавя към известието. NotificationService наследява UNNotificationServiceExtension и преопределя метода didReceive. В примера е показана обработка на опционални полета, създаване на прикачен файл и извикване на 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, и разширението се активира само за известия със съответната категория в payload-а.
Често задавани въпроси
Service Extension модифицира съдържанието преди показване на известието — добавя медия, променя текст, декриптира данни. Content Extension заменя интерфейса на известието с персонализиран след взаимодействие на потребителя. Service Extension работи преди показване, Content Extension — след това.
Системата отделя 30 секунди за изпълнение на код в didReceive. Ако обработката не приключи за това време, се извиква serviceExtensionTimeWillExpire, където трябва да се предаде текущият резултат. Препоръчваме да се вместите в 10–15 секунди, като вземете предвид зареждането на прикачени файлове.
Да, SwiftUI се поддържа в Content Extension от iOS 16. View се обвива в UIHostingController и се добавя към storyboard. Въпреки това, поради ограниченията на паметта, се препоръчва използването на SwiftUI само за прости интерфейси с минимален брой елементи.
При грешка при зареждане или надвишаване на времевия лимит, просто извикайте completion handler с оригиналното съдържание без прикачен файл. Системата ще покаже известието в стандартен вид без медия. Логирайте грешките чрез OSLog за диагностика, но не блокирайте показването на известието.
Разширението работи в изолиран процес с лимит около 50 MB. При надвишаване на лимита системата убива процеса чрез watchdog. Избягвайте зареждане на големи файлове, съхранение на изображения в паметта и изтичане на памет при работа с URLSession.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също