Notification Service Extension — este o extensie iOS care interceptează notificarea push înainte de afișarea ei utilizatorului și permite modificarea conținutului. Extensia poate decripta date criptate, descărca atașamente media, modifica textul sau adăuga câmpuri personalizate. Conform Apple Developer, 2025, Notification Service Extension are până la 30 de secunde pentru a executa sarcina în fundal.
Principalele
Notification Service Extension — este o extensie de aplicație în iOS care se lansează înainte de afișarea notificării push. Permite serverului să trimită un payload minim, iar extensia să îl completeze cu conținut: să descarce imagini, să decripteze date, să înlocuiască textul. Utilizatorul vede notificarea deja pregătită, procesată.
Când iOS primește o notificare push, sistemul verifică prezența extensiei pentru această aplicație. Dacă extensia este înregistrată, iOS o lansează într-un proces de fundal și transmite conținutul notificării prin metoda didReceive(_:withContentHandler:). Extensia procesează conținutul și apelează contentHandler cu conținutul modificat. Dacă extensia nu reușește în 30 de secunde, sistemul afișează notificarea originală.
Service Extension este necesară în scenariile în care conținutul notificării necesită procesare pe dispozitiv. Comunicații sigure: serverul trimite un payload criptat, extensia îl decriptează local. Notificări media bogate: serverul trimite un URL de imagine, extensia îl descarcă și îl atașează. Localizare dinamică: extensia înlocuiește textul în limba dispozitivului.
| Scenariu | Fără extensie | Cu extensie |
|---|---|---|
| Imagine | Nu este suportat | Se descarcă și se afișează |
| Criptare | Serverul păstrează cheia | Decriptare pe dispozitiv |
| Text | Setat rigid pe server | Înlocuire dinamică |
| Validare | Nu se verifică | Anularea notificărilor malițioase |
Notification Service Extension funcționează într-un mediu limitat. Timpul maxim de execuție — 30 de secunde. Extensia nu are acces la stocarea principală a aplicației (cu excepția App Group). Dimensiunea extensiei este limitată la 50 MB. La depășirea timpului, sistemul apelează contentHandler cu conținutul original și toate modificările se pierd.
În Xcode, Notification Service Extension se adaugă prin crearea unui nou target de tip Notification Service Extension. Xcode generează un șablon de clasă NotificationService care moștenește UNNotificationServiceExtension, cu două metode: didReceive și serviceExtensionTimeWillExpire.
În Xcode alegeți File → New → Target → Notification Service Extension. Specificați numele (de exemplu, PushNotificationService) și limbajul Swift. Asigurați-vă că targetul a fost adăugat la aplicația principală și are semnătura corectă. După creare, va fi generată clasa NotificationService.swift cu implementarea de bază.
Info.plist al extensiei conține cheia NSExtension cu subcheile NSExtensionPointIdentifier (com.apple.usernotifications.service) și NSExtensionPrincipalClass (numele controlerului). Opțional, se poate specifica NSExtensionAttributes cu regulile de activare ale extensiei. Aceste setări sunt generate automat de Xcode.
Implementarea de bază suprascrie didReceive, modifică conținutul notificării și apelează contentHandler. Dacă procesarea durează prea mult, se apelează serviceExtensionTimeWillExpire, unde trebuie să finalizați lucrul cu starea curentă.
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 = "[Procesat] \(bestAttemptContent.title)"
contentHandler?(bestAttemptContent)
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler,
let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
Una dintre aplicațiile cheie ale Service Extension este decriptarea conținutului notificării pe dispozitiv. Serverul trimite un payload criptat, iar extensia îl decriptează folosind o cheie stocată în Keychain sau App Group. Aceasta garantează că conținutul nu poate fi interceptat în timpul transmisiei.
Serverul criptează corpul notificării utilizând o cheie simetrică (AES-256). Cheia de criptare este convenită în prealabil între client și server. Extensia primește un șir criptat în câmpul data al payloadului, îl decriptează și îl plasează în câmpurile notificării. Cheia utilizatorului poate fi obținută din Keychain după autentificare.
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)
}
Cheia de decriptare nu trebuie stocată în codul extensiei sau în NSUserDefaults. Utilizați iOS Keychain cu acces prin App Group, astfel încât atât aplicația cât și extensia să poată citi cheia. Pentru generarea cheii pe client, utilizați Security.framework cu algoritmul AES-256-GCM.
Cea mai frecventă utilizare a Notification Service Extension — descărcarea imaginilor, GIF-urilor și videourilor pentru afișarea ulterioară în notificare. Serverul trimite URL-ul fișierului media, iar extensia îl descarcă, îl salvează într-un director temporar și creează UNNotificationAttachment.
Extensia primește URL-ul imaginii din câmpul payload al notificării. Folosind URLSession, extensia descarcă fișierul într-un director temporar. După finalizarea descărcării, se creează UNNotificationAttachment cu URL-ul local. Atașamentul este transmis în conținutul modificat. iOS afișează automat imaginea în interfața standard sau în 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 suportă următoarele formate pentru afișarea în notificări: JPEG, PNG, GIF (statice), video MPEG-4 până la 50 MB. Pentru fișiere audio, sunt suportate MP3, AAC și ALAC. Important: toate fișierele media trebuie descărcate în limita de 30 de secunde. Pentru fișiere mari, se recomandă tăierea pe server sau descărcarea progresivă.
Gestionarea limitei de 30 de secunde — sarcina cheie în dezvoltarea Notification Service Extension. Dacă extensia nu reușește să finalizeze procesarea, sistemul apelează serviceExtensionTimeWillExpire și afișează conținutul original. Trebuie prevăzute scenarii de rezervă pentru fiecare tip de procesare.
Împărțiți sarcinile pe priorități. Modificările critice (decriptare, localizare de bază) executați-le în primul rând. Îmbunătățirile opționale (descărcarea imaginilor, îmbogățirea textului) — în al doilea rând. Utilizați URLSession cu timeout pentru cererile de rețea, pentru a nu consuma întreaga limită pe o singură operație.
Dacă descărcarea imaginii a eșuat sau decriptarea payloadului a returnat o eroare, extensia trebuie să apeleze contentHandler cu conținutul original. Nu finalizați niciodată extensia fără a apela contentHandler — aceasta duce la pierderea notificării. Rezerva sigură trebuie întotdeauna prevăzută în codul extensiei.
override func didReceive(
request: UNNotificationRequest,
withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
let content = (request.content.mutableCopy()
as? UNMutableNotificationContent) ?? request.content
// Sarcină critică: decriptare
var decryptedContent = tryDecryptPayload(content)
// Sarcină opțională: media
guard let mediaUrl = decryptedContent.userInfo["media_url"]
as? String else {
handler(decryptedContent)
return
}
downloadAndAttachMedia(
content: decryptedContent,
mediaUrl: mediaUrl,
handler: handler
)
}
Pentru testarea Notification Service Extension utilizați Xcode: selectați targetul extensiei, rulați pe simulator și trimiteți o notificare push prin terminal sau Firebase Console. Logați fiecare etapă de procesare prin os_log — aceasta ajută la diagnosticarea problemelor de timp și erorilor de încărcare.
Întrebări frecvente
Sistemul va apela serviceExtensionTimeWillExpire, după care va afișa notificarea originală fără modificări. Toate fișierele descărcate și modificările vor fi anulate.
Da, dacă apelați contentHandler cu conținut gol (UNNotificationContent cu câmpuri goale), notificarea nu va fi afișată. Aceasta se utilizează pentru filtrarea notificărilor spam sau a datelor incorecte.
Tokenul poate fi transmis în userInfo al payloadului notificării sau obținut din Keychain prin App Group. Nu se recomandă stocarea tokenurilor în UserDefaults ale extensiei.
Extensia trebuie să fie semnată cu același certificat de dezvoltator ca și aplicația principală. Pentru producție este necesar certificatul de producție cu capability Push Notifications activată.
Conectați dispozitivul la Xcode, selectați targetul extensiei în schema de lansare și trimiteți o notificare push prin Firebase Console. Breakpoints în extensie funcționează la fel ca în aplicația principală.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și