Notification Extension هي آلية في iOS تتيح تعديل محتوى ومظهر الإشعارات الفورية قبل عرضها للمستخدم. تعمل الامتدادات على جانب نظام التشغيل في عملية منفصلة: UNNotificationServiceExtension يعالج المحتوى الوارد، بينما UNNotificationContentExtension يدير الواجهة. وفقًا لـ Apple Developer Documentation, 2026، يحصل Service Extension على ما يصل إلى 30 ثانية لتنفيذ المهام قبل عرض الإشعار. هذا القيد بالغ الأهمية عند تنزيل المرفقات أو فك تشفير البيانات.
الملخص
Notification Extension هو مكون برمجي في iOS يوسع السلوك القياسي للإشعارات الفورية بإضافة إمكانية تعديل المحتوى وتخصيص الواجهة. على عكس الإشعارات العادية التي يعرضها النظام بتنسيق قياسي، تتيح الامتدادات للمطور التأثير على المحتوى قبل العرض وإنشاء واجهة مستخدم فريدة.
توفر Apple نوعين من Notification Extension لأغراض مختلفة: UNNotificationServiceExtension يتولى معالجة الحمولة الواردة، بينما UNNotificationContentExtension يدير العرض. يتم تشغيل Service Extension قبل عرض الإشعار وله وقت تنفيذ محدود — يصل إلى 30 ثانية وفقًا لـ Apple Developer Documentation. يتم تنشيط Content Extension بعد تفاعل المستخدم مع الإشعار ويعرض عرضًا مخصصًا.
يتم عرض الإشعار الفوري القياسي في iOS تلقائيًا بواسطة النظام بناءً على حقول alert و title و subtitle من حمولة JSON. Notification Extension يعترض التحكم: Service Extension يتلقى الحمولة الخام ويعدلها ويمررها إلى النظام للعرض. Content Extension يستبدل البانر القياسي بواجهة مخصصة مع أي عناصر تحكم.
عندما يستلم الجهاز إشعارًا فوريًا بمفتاح mutable-content: 1، يقوم النظام بتشغيل Service Extension في عملية منفصلة. عملية الامتداد معزولة عن التطبيق الرئيسي ولها بيئة خاصة بها بحد ذاكرة 50 ميجابايت. بعد اكتمال المعالجة، يستدعي الامتداد completion handler، ويمرر UNNotificationContent المعدل إلى النظام للعرض.
UNNotificationServiceExtension هو الأداة الرئيسية لتعديل الإشعارات الفورية برمجيًا قبل عرضها للمستخدم. يتم تنشيط الامتداد تلقائيًا عند استلام إشعار به علم mutable-content: 1 في حمولته. في غضون 30 ثانية، يمكن للامتداد تنزيل مرفق وسائط، تغيير النص، فك تشفير البيانات المشفرة أو إثراء المحتوى.
يقوم الامتداد بتنفيذ طريقتين رئيسيتين من بروتوكول UNNotificationServiceExtension. طريقة didReceive تستلم الطلب الوارد مع UNNotificationRequest الخام وتتيح التعديل عبر completion handler مع UNNotificationContent جديد. يتم استدعاء طريقة serviceExtensionTimeWillExpire بواسطة النظام قبل ثانية من انتهاء المهلة — فيها يجب إكمال المعالجة وتمرير النتيجة الحالية (ربما الجزئية).
لنفترض سيناريو حيث يرسل الخادم إشعارًا مع رابط صورة في حقل مخصص. يقوم 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. يختار النظام تلقائيًا الامتداد المناسب بناءً على فئة الإشعار المستلم. يتم بناء الواجهة عبر storyboard باستخدام مكونات UIKit القياسية أو SwiftUI View.
يدعم Content Extension أزرارًا مخصصة ومعالجات نقر معرفة في UNNotificationAction. UNNotificationAction يتم إنشاؤه في مرحلة تسجيل الفئة ويمكن أن يدعم إدخال النص عبر UNTextInputNotificationAction. عندما يضغط المستخدم على زر، يتلقى الامتداد استدعاء didReceive مع معرف الإجراء ويمكنه تنفيذ المنطق المقابل — فتح رابط، إرسال طلب إلى الخادم أو تحديث الواجهة.
يعمل Content Extension في عملية معزولة مع دورة تشغيل خاصة به وحد ذاكرة حوالي 50 ميجابايت. أداء الامتداد بالغ الأهمية لأن watchdog في النظام ينهي العملية عند تجاوز الحدود. يُوصى بتجنب الحسابات الثقيلة وتحميل الصور الكبيرة والطلبات الشبكية الطويلة داخل Content Extension.
UNNotificationAttachment هو كائن يضيف ملف وسائط إلى إشعار فوري: صورة، فيديو، صوت أو GIF. يتم إنشاء المرفق من رابط ملف محلي يجب أن يكون في بيئة الامتداد. يجب ألا يتجاوز الحد الأقصى لحجم المرفق 10 ميجابايت، وإلا سيرفض النظام المرفق عند إنشائه.
تدعم Apple مجموعة محدودة من التنسيقات لمرفقات الوسائط. الصور — JPEG، PNG، GIF (بما في ذلك المتحركة)، TIFF. الفيديو — MPEG، MP4، MOV بأقصى مدة 30 ثانية. الصوت — MP3، AAC، WAV، CAF. لكل تنسيق يمكن تحديد النوع عبر UNNotificationAttachmentOptionsTypeHintKey، مما يساعد النظام على معالجة الملف بشكل صحيح.
نظرًا لأن حمولة الإشعار تحتوي فقط على رابط وليس الملف نفسه، يجب تنفيذ تنزيل المرفق داخل 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، ويتم تنشيط الامتداد فقط للإشعارات ذات الفئة المطابقة في الحمولة.
الأسئلة الشائعة
Service Extension يعدل المحتوى قبل عرض الإشعار — يضيف وسائط ويغير النص ويفك تشفير البيانات. Content Extension يستبدل واجهة الإشعار بواجهة مخصصة بعد تفاعل المستخدم. Service Extension يعمل قبل العرض، Content Extension يعمل بعد العرض.
يخصص النظام 30 ثانية لتنفيذ الكود في didReceive. إذا لم يكتمل المعالجة خلال هذا الوقت، يتم استدعاء serviceExtensionTimeWillExpire حيث يجب تمرير النتيجة الحالية. يُوصى بالبقاء ضمن 10–15 ثانية مع مراعاة تنزيل المرفقات.
نعم، SwiftUI مدعوم في Content Extension بدءًا من iOS 16. يتم تغليف العرض في UIHostingController وإضافته إلى storyboard. ومع ذلك، نظرًا لحدود الذاكرة، يُوصى باستخدام SwiftUI فقط للواجهات البسيطة بأقل عدد من العناصر.
في حالة خطأ التنزيل أو تجاوز الوقت، ما عليك سوى استدعاء completion handler بالمحتوى الأصلي بدون مرفق. سيعرض النظام الإشعار بالشكل القياسي بدون وسائط. سجل الأخطاء عبر OSLog للتشخيص، لكن لا تمنع عرض الإشعار.
يعمل الامتداد في عملية معزولة بحد ذاكرة حوالي 50 ميجابايت. عند تجاوزه، ينهي النظام العملية عبر watchdog. تجنب تحميل الملفات الكبيرة وتخزين الصور في الذاكرة والتسريبات عند العمل مع URLSession.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا