Notification Service Extension είναι μια επέκταση iOS που υποκλέπτει την ειδοποίηση push αμέσως μετά τη λήψη, αλλά πριν από την εμφάνιση στον χρήστη. Η επέκταση μπορεί να αποκρυπτογραφήσει κρυπτογραφημένο payload, να κατεβάσει και να επισυνάψει αρχείο πολυμέσων, να αλλάξει το κείμενο ή τον τίτλο της ειδοποίησης σε πραγματικό χρόνο. Σύμφωνα με το Apple Developer Documentation (2025), για την ενεργοποίηση της επέκτασης, ο διακομιστής πρέπει να στείλει το κλειδί mutable-content:1 στα χαρακτηριστικά της ειδοποίησης — αυτή είναι η μόνη προϋπόθεση για την εκκίνηση του UNNotificationServiceExtension.
Κύρια σημεία
Notification Service Extension είναι μια επέκταση εφαρμογής στο iOS που υποκλέπτει την εισερχόμενη ειδοποίηση push στην πλευρά της συσκευής και επιτρέπει την αλλαγή του περιεχομένου της πριν τη δει ο χρήστης. Είναι ο μόνος τύπος επέκτασης ειδοποιήσεων που λειτουργεί με περιεχόμενο, όχι με εμφάνιση.
Η βασική διαφορά από το Notification Content Extension: Το Service Extension λειτουργεί πριν από την εμφάνιση της ειδοποίησης και μπορεί να αλλάξει τον τίτλο, το σώμα, το αρχείο ήχου και τα συνημμένα. Το Content Extension λειτουργεί μετά την εμφάνιση και διαχειρίζεται μόνο την οπτική παρουσίαση της έτοιμης ειδοποίησης. Αυτές οι δύο επεκτάσεις μπορούν να λειτουργήσουν μαζί: Το Service Extension κατεβάζει την εικόνα και το Content Extension την εμφανίζει σε προσαρμοσμένη διεπαφή.
Η επέκταση ενεργοποιείται αυτόματα κατά τη λήψη μιας ειδοποίησης push με το χαρακτηριστικό mutable-content:1 στο λεξικό aps. Το iOS εκκινεί την επέκταση στο παρασκήνιο, της μεταδίδει το αρχικό UNNotificationRequest και περιμένει την τροποποιημένη έκδοση για εμφάνιση.
UNNotificationServiceExtension λαμβάνει το πλήρες UNNotificationRequest με το αρχικό περιεχόμενο. Η επέκταση μπορεί να τροποποιήσει οποιοδήποτε πεδίο UNNotificationContent: title, subtitle, body, userInfo, attachments και sound. Οι αλλαγές εφαρμόζονται πριν από την εμφάνιση της ειδοποίησης.
Αποκρυπτογράφηση περιεχομένου — αν η ειδοποίηση push περιέχει κρυπτογραφημένο payload, η επέκταση το αποκρυπτογραφεί πριν από την εμφάνιση. Λήψη πολυμέσων — επισύναψη εικόνας ή βίντεο στην ειδοποίηση. Προσαρμογή τοπικών ρυθμίσεων — προσαρμογή του κειμένου ειδοποίησης στις περιφερειακές ρυθμίσεις της συσκευής. Εμπλουτισμός δεδομένων — προσθήκη πρόσθετων πληροφοριών από τοπικό χώρο αποθήκευσης ή προσωρινή μνήμη.
Σύμφωνα με την Apple, το πιο συνηθισμένο σενάριο μεταξύ εφαρμογών είναι η λήψη εικόνων για πλούσιες ειδοποιήσεις πολυμέσων. Ο διακομιστής στέλνει τη διεύθυνση URL της εικόνας στο payload, η επέκταση την κατεβάζει σε έναν προσωρινό κατάλογο και δημιουργεί UNNotificationAttachment, το οποίο το σύστημα εμφανίζει στην τυπική ή προσαρμοσμένη διεπαφή.
Η επέκταση μπορεί να ξαναγράψει πλήρως το κείμενο της ειδοποίησης, να αντικαταστήσει τον τίτλο ή να προσθέσει υπότιτλο. Για παράδειγμα, μια εφαρμογή ανταλλαγής μηνυμάτων μπορεί να λάβει μια κρυπτογραφημένη ειδοποίηση, να την αποκρυπτογραφήσει στην επέκταση και να εμφανίσει αναγνώσιμο κείμενο. Ή μια εφαρμογή ειδήσεων μπορεί να προσθέσει την κατηγορία είδησης στον υπότιτλο πριν από την εμφάνιση.
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
let content = request.content.mutableCopy()
as! UNMutableNotificationContent
if let imageURL = content.userInfo["media-url"]
as? String {
downloadAndAttach(imageURL: imageURL,
content: content,
handler: contentHandler)
}
}
UNNotificationServiceExtension — η βασική κλάση από την οποία κληρονομεί το Service Extension. Η κλάση ορίζει δύο μεθόδους κύκλου ζωής: didReceive(_:withContentHandler:) — την κύρια μέθοδο επεξεργασίας, και serviceExtensionTimeWillExpire() — τον χειριστή λήξης χρόνου.
didReceive(_:withContentHandler:) καλείται κατά τη λήψη μιας ειδοποίησης. Η επέκταση λαμβάνει UNNotificationRequest και το closure contentHandler που πρέπει να κληθεί με το τροποποιημένο UNMutableNotificationContent. Η επέκταση υποχρεούται να καλέσει το contentHandler — αν δεν το κάνει, το iOS θα εμφανίσει την αρχική ειδοποίηση μετά τη λήξη του χρονικού ορίου.
Σημαντικό: η επέκταση μπορεί να επεξεργαστεί μόνο μία ειδοποίηση τη φορά. Αν φτάσουν πολλές ειδοποιήσεις ταυτόχρονα, το iOS δημιουργεί ξεχωριστά στιγμιότυπα της επέκτασης για κάθε μία. Δεν μπορεί να χρησιμοποιηθεί καθολική κατάσταση για σειριακή επεξεργασία.
serviceExtensionTimeWillExpire() καλείται από το σύστημα όταν ο υπόλοιπος χρόνος εκτέλεσης πλησιάζει στο τέλος του. Σε αυτήν τη μέθοδο, πρέπει να κληθεί αμέσως το contentHandler με το περιεχόμενο που είναι έτοιμο εκείνη τη στιγμή — ακόμα κι αν το αρχείο πολυμέσων δεν έχει ακόμη ληφθεί. Αν δεν κληθεί το contentHandler σε αυτήν τη μέθοδο, το iOS θα εμφανίσει την αρχική ειδοποίηση.
Συνιστάται να διατηρείται ελάχιστα αποδεκτό περιεχόμενο σε αυτήν τη μέθοδο — για παράδειγμα, μια ειδοποίηση με κείμενο και τίτλο, αλλά χωρίς την εικόνα της οποίας η λήψη δεν ολοκληρώθηκε εγκαίρως.
UNNotificationAttachment — ένα αντικείμενο που δημιουργείται από την επέκταση για την επισύναψη αρχείου πολυμέσων στην ειδοποίηση. Η επέκταση κατεβάζει το αρχείο από το δίκτυο, το αποθηκεύει σε έναν προσωρινό κατάλογο και δημιουργεί UNNotificationAttachment με καθορισμό του τύπου περιεχομένου.
Το UNNotificationAttachment δημιουργείται χρησιμοποιώντας τον αρχικοποιητή init(identifier:url:options:). Η διεύθυνση URL πρέπει να δείχνει σε ένα τοπικό αρχείο στον προσωρινό κατάλογο που είναι προσβάσιμος από την επέκταση. Μετά τη δημιουργία, το συνημμένο προστίθεται στον πίνακα attachments του UNMutableNotificationContent.
Η Apple συνιστά τη χρήση URLSession με διαμόρφωση παρασκηνίου για λήψη — κατά τη χρήση τυπικού URLSession, η λήψη μπλοκάρει το νήμα και καταναλώνει χρόνο από το όριο των 30 δευτερολέπτων. Το URLSession παρασκηνίου συνεχίζει τη λήψη ακόμα και μετά τον τερματισμό της επέκτασης, και το αποτέλεσμα μπορεί να χρησιμοποιηθεί στην επόμενη εκκίνηση.
Αν ο διακομιστής στέλνει κρυπτογραφημένη ειδοποίηση, η επέκταση πρέπει να αποκρυπτογραφήσει το payload πριν από την κλήση του contentHandler. Η αποκρυπτογράφηση συνήθως περιλαμβάνει αίτημα κλειδιού από το Keychain ή το App Group, αποκρυπτογράφηση μέσω CommonCrypto και αντικατάσταση του body ή userInfo της ειδοποίησης. Σε περίπτωση σφάλματος αποκρυπτογράφησης, το contentHandler πρέπει να κληθεί με το αρχικό περιεχόμενο — ώστε ο χρήστης να δει τουλάχιστον ότι έφτασε η ειδοποίηση, ακόμα κι αν είναι δυσανάγνωστη.
func downloadAndAttach(
imageURL: String,
content: UNMutableNotificationContent,
handler: @escaping (UNNotificationContent) -> Void
) {
let task = URLSession.shared.dataTask(with:
URL(string: imageURL)!) { data, _, _ in
let url = FileManager.default
.temporaryDirectory
.appendingPathComponent("image.jpg")
try? data?.write(to: url)
let attachment = try? UNNotificationAttachment(
identifier: "image", url: url)
content.attachments = [attachment].compactMap { $0 }
handler(content)
}
task.resume()
}
Notification Service Extension λειτουργεί μέσα σε αυστηρά χρονικά πλαίσια. Το iOS διαθέτει σταθερό χρόνο εκτέλεσης — περίπου 30 δευτερόλεπτα από τη στιγμή της ενεργοποίησης. Αν η επέκταση δεν καλέσει το contentHandler εντός αυτού του χρόνου, το σύστημα τερματίζει αναγκαστικά τη διαδικασία και εμφανίζει την αρχική ειδοποίηση χωρίς αλλαγές.
Συνιστάται η εφαρμογή πολυεπίπεδου fallback: πρώτα προσπαθήστε να κατεβάσετε τα πολυμέσα, σε περίπτωση επιτυχίας — καλέστε contentHandler με πλήρες περιεχόμενο; σε περίπτωση αποτυχίας — καλέστε contentHandler με κείμενο αλλά χωρίς πολυμέσα; σε περίπτωση κρίσιμου σφάλματος — μεταδώστε το αρχικό περιεχόμενο. Αυτή η προσέγγιση εγγυάται ότι ο χρήστης θα βλέπει πάντα μια ειδοποίηση, όχι μια κενή οθόνη.
Σύμφωνα με την Apple, η συχνότερη αιτία χρονικών ορίων είναι η λήψη μεγάλων αρχείων πολυμέσων σε αργή σύνδεση. Για τη μείωση του κινδύνου, συνιστάται η βελτιστοποίηση του μεγέθους εικόνας στον διακομιστή — αποστολή προεπισκοπήσεων έως 300 KB αντί για πλήρη ανάλυση. Οι εικόνες πλήρους ανάλυσης θα πρέπει να μεταφορτώνονται κατά το άνοιγμα της εφαρμογής.
Για την παρακολούθηση χρονικών ορίων και σφαλμάτων της επέκτασης, μπορεί να χρησιμοποιηθεί το os_log για εγγραφή διαγνωστικών μηνυμάτων στο Unified Logging System. Αν και η άμεση καταγραφή σε αρχείο στην επέκταση είναι δύσκολη, το os_log επιτρέπει την ανάλυση απόδοσης μέσω του Console.app στη συσκευή προγραμματιστή. Η Apple συνιστά την προσθήκη μετρήσεων σε κάθε κλήση didReceive — χρόνος λήψης, μέγεθος αρχείου, αποτέλεσμα λειτουργίας.
override func serviceExtensionTimeWillExpire() {
let fallback = bestEffortContent as?
UNMutableNotificationContent
?? request.content.mutableCopy()
as! UNMutableNotificationContent
contentHandler(fallback)
}
Συχνές ερωτήσεις
Ο διακομιστής προσθέτει το κλειδί mutable-content:1 στο λεξικό aps της ειδοποίησης push. Χωρίς αυτήν την παράμετρο, το σύστημα αγνοεί την επέκταση και εμφανίζει την τυπική ειδοποίηση.
Όχι. Το mutable-content:1 είναι υποχρεωτική προϋπόθεση για την ενεργοποίηση του Service Extension. Αν το κλειδί λείπει ή έχει οριστεί σε 0, η ειδοποίηση εμφανίζεται χωρίς κλήση της επέκτασης.
Το iOS τερματίζει αναγκαστικά την επέκταση και εμφανίζει την αρχική ειδοποίηση χωρίς αλλαγές. Για να το αποφύγετε, εφαρμόστε το serviceExtensionTimeWillExpire() με ελάχιστα αποδεκτό περιεχόμενο.
Μέσω App Group (κοινόχρηστο UserDefaults ή αρχείο) ή Keychain με κοινόχρηστη πρόσβαση μεταξύ εφαρμογής και επέκτασης. Η άμεση μεταφορά κλειδιών στο payload της ειδοποίησης δεν είναι ασφαλής.
Έως 4 συνημμένα ανά ειδοποίηση, το καθένα έως 50 MB. Το συνολικό μέγεθος των συνημμένων επηρεάζει τον χρόνο λήψης — όσο περισσότερα αρχεία, τόσο μεγαλύτερος ο κίνδυνος χρονικού ορίου.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης