Notification Service Extension — je iOS rozšíření, které zachytí push oznámení před jeho zobrazením uživateli a umožňuje upravit obsah. Rozšíření může dešifrovat zašifrovaná data, stáhnout multimediální přílohy, změnit text nebo přidat vlastní pole. Podle Apple Developer, 2025 má Notification Service Extension až 30 sekund na provedení úlohy na pozadí.
Hlavní
Notification Service Extension — je rozšíření aplikace v iOS, které se spouští před zobrazením push oznámení. Umožňuje serveru odeslat minimální payload a rozšíření jej doplnit obsahem: stáhnout obrázky, dešifrovat data, nahradit text. Uživatel vidí hotové, zpracované oznámení.
Když iOS obdrží push oznámení, systém zkontroluje přítomnost rozšíření pro tuto aplikaci. Pokud je rozšíření zaregistrováno, iOS jej spustí v procesu na pozadí a předá obsah oznámení prostřednictvím metody didReceive(_:withContentHandler:). Rozšíření zpracuje obsah a zavolá contentHandler s upraveným obsahem. Pokud rozšíření nestihne práci do 30 sekund, systém zobrazí původní oznámení.
Service Extension je nezbytný ve scénářích, kde obsah oznámení vyžaduje zpracování na zařízení. Bezpečná komunikace: server odešle zašifrovaný payload, rozšíření jej lokálně dešifruje. Bohatá multimediální oznámení: server odešle URL obrázku, rozšíření jej stáhne a připojí. Dynamická lokalizace: rozšíření nahradí text v jazyce zařízení.
| Scénář | Bez rozšíření | S rozšířením |
|---|---|---|
| Obrázek | Není podporováno | Stahuje se a zobrazuje |
| Šifrování | Server uchovává klíč | Dešifrování na zařízení |
| Text | Pevně nastaven na serveru | Dynamické nahrazení |
| Validace | Nekontroluje se | Zrušení škodlivých oznámení |
Notification Service Extension pracuje v omezeném prostředí. Maximální doba běhu — 30 sekund. Rozšíření nemá přístup k hlavnímu úložišti aplikace (kromě App Group). Velikost rozšíření je omezena na 50 MB. Při překročení času systém zavolá contentHandler s původním obsahem a všechny změny jsou ztraceny.
V Xcode se Notification Service Extension přidá vytvořením nového targetu typu Notification Service Extension. Xcode vygeneruje šablonu třídy NotificationService dědící z UNNotificationServiceExtension se dvěma metodami: didReceive a serviceExtensionTimeWillExpire.
V Xcode zvolte File → New → Target → Notification Service Extension. Zadejte název (např. PushNotificationService) a jazyk Swift. Ujistěte se, že target byl přidán k hlavní aplikaci a má správný podpis. Po vytvoření bude vygenerována třída NotificationService.swift se základní implementací.
Info.plist rozšíření obsahuje klíč NSExtension s podklíči NSExtensionPointIdentifier (com.apple.usernotifications.service) a NSExtensionPrincipalClass (název vašeho kontroleru). Volitelně lze zadat NSExtensionAttributes s pravidly aktivace rozšíření. Tato nastavení Xcode generuje automaticky.
Základní implementace přepíše didReceive, upraví obsah oznámení a zavolá contentHandler. Pokud zpracování trvá příliš dlouho, je zavolána serviceExtensionTimeWillExpire, kde je třeba dokončit práci s aktuálním stavem.
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 = "[Zpracováno] \(bestAttemptContent.title)"
contentHandler?(bestAttemptContent)
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler,
let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
Jedním z klíčových použití Service Extension je dešifrování obsahu oznámení na zařízení. Server odešle zašifrovaný payload a rozšíření jej dešifruje pomocí klíče uloženého v Keychain nebo App Group. To zaručuje, že obsah není přístupný pro zachycení během přenosu.
Server zašifruje tělo oznámení pomocí symetrického klíče (AES-256). Šifrovací klíč je předem dohodnut mezi klientem a serverem. Rozšíření obdrží zašifrovaný řetězec v poli data payloadu, dešifruje jej a vloží do polí oznámení. Uživatelský klíč lze získat z Keychain po autentizaci.
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)
}
Klíč k dešifrování by neměl být uložen v kódu rozšíření nebo NSUserDefaults. Použijte iOS Keychain s přístupem přes App Group, aby jak aplikace, tak rozšíření mohly klíč číst. Pro generování klíče na straně klienta použijte Security.framework s algoritmem AES-256-GCM.
Nejčastější použití Notification Service Extension — stažení obrázků, GIFů a videí pro následné zobrazení v oznámení. Server odešle URL mediálního souboru, rozšíření jej stáhne, uloží do dočasného adresáře a vytvoří UNNotificationAttachment.
Rozšíření obdrží URL obrázku z pole payload oznámení. Pomocí URLSession rozšíření stáhne soubor do dočasného adresáře. Po dokončení stažení je vytvořen UNNotificationAttachment s lokálním URL. Příloha je předána upravenému obsahu. iOS automaticky zobrazí obrázek ve standardním rozhraní nebo v Notification Content Extension.
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 podporuje následující formáty pro zobrazení v oznámeních: JPEG, PNG, GIF (statické), MPEG-4 video do 50 MB. Pro zvukové soubory jsou podporovány MP3, AAC a ALAC. Důležité: všechny mediální soubory musí být staženy v rámci 30sekundového limitu. Pro velké soubory se doporučuje ořezání na serveru nebo progresivní stahování.
Správa 30sekundového limitu — klíčový úkol při vývoji Notification Service Extension. Pokud rozšíření nestihne dokončit zpracování, systém zavolá serviceExtensionTimeWillExpire a zobrazí původní obsah. Pro každý typ zpracování je třeba předvídat záložní scénáře.
Rozdělte úkoly podle priorit. Kritické úpravy (dešifrování, základní lokalizace) provádějte jako první. Volitelná vylepšení (stažení obrázků, obohacení textu) — jako druhé. Pro síťové požadavky používejte URLSession s timeouty, abyste nevyčerpali celý limit na jednu operaci.
Pokud se stažení obrázku nezdařilo nebo dešifrování payloadu vrátilo chybu, rozšíření by mělo zavolat contentHandler s původním obsahem. Nikdy neukončujte rozšíření bez zavolání contentHandler — to vede ke ztrátě oznámení. Bezpečný fallback by měl být vždy předvídán v kódu rozšíření.
override func didReceive(
request: UNNotificationRequest,
withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
let content = (request.content.mutableCopy()
as? UNMutableNotificationContent) ?? request.content
// Kritický úkol: dešifrování
var decryptedContent = tryDecryptPayload(content)
// Volitelný úkol: média
guard let mediaUrl = decryptedContent.userInfo["media_url"]
as? String else {
handler(decryptedContent)
return
}
downloadAndAttachMedia(
content: decryptedContent,
mediaUrl: mediaUrl,
handler: handler
)
}
Pro testování Notification Service Extension použijte Xcode: vyberte target rozšíření, spusťte na simulátoru a odešlete push oznámení přes terminál nebo Firebase Console. Logujte každou fázi zpracování pomocí os_log — to pomáhá diagnostikovat problémy s časováním a chyby načítání.
Často kladené otázky
Systém zavolá serviceExtensionTimeWillExpire, poté zobrazí původní oznámení beze změn. Všechny stažené soubory a úpravy budou zahozeny.
Ano, pokud zavoláte contentHandler s prázdným obsahem (UNNotificationContent s prázdnými poli), oznámení nebude zobrazeno. Používá se k filtrování spamových oznámení nebo nesprávných dat.
Token lze předat v userInfo payloadu oznámení nebo získat z Keychain přes App Group. Ukládání tokenů v UserDefaults rozšíření se nedoporučuje.
Rozšíření musí být podepsáno stejným vývojářským certifikátem jako hlavní aplikace. Pro produkci je vyžadován produkční certifikát s povolenou capability Push Notifications.
Připojte zařízení k Xcode, vyberte target rozšíření ve schématu spuštění a odešlete push oznámení přes Firebase Console. Breakpoints v rozšíření fungují stejně jako v hlavní aplikaci.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také