Notification Service Extension هي إضافة iOS تعترض الإشعار الفوري فور استلامه ولكن قبل عرضه للمستخدم. يمكن للإضافة فك تشفير الحمولة المشفرة، وتنزيل وإرفاق الملفات الوسائطية، وتغيير نص الإشعار أو عنوانه في الوقت الفعلي. وفقاً لوثائق مطوري Apple (2025)، لتفعيل الإضافة يجب على الخادم إرسال المفتاح mutable-content:1 في سمات الإشعار — هذا هو الشرط الوحيد لتشغيل UNNotificationServiceExtension.
النقاط الرئيسية
Notification Service Extension هي إضافة تطبيق في iOS تعترض الإشعار الفوري الوارد على جهاز المستخدم وتسمح بتعديل محتواه قبل أن يراه المستخدم. هذا هو النوع الوحيد من إضافات الإشعارات الذي يعمل مع المحتوى وليس مع العرض.
الفرق الرئيسي عن Notification Content Extension: تعمل Service Extension قبل عرض الإشعار ويمكنها تغيير العنوان والنص وملف الصوت والمرفقات. تعمل Content Extension بعد العرض وتدير فقط التمثيل البصري للإشعار الجاهز. يمكن لهاتين الإضافتين العمل معاً: تقوم Service Extension بتنزيل صورة، وتعرضها Content Extension في واجهة مخصصة.
يتم تفعيل الإضافة تلقائياً عند استلام إشعار فوري يحتوي على السمة mutable-content:1 في قاموس aps. يقوم iOS بتشغيل الإضافة في الخلفية، ويمرر لها طلب UNNotificationRequest الأصلي، وينتظر نسخة معدلة للعرض.
UNNotificationServiceExtension تستلم طلب UNNotificationRequest الكامل مع المحتوى الأصلي. يمكن للإضافة تعديل أي حقول من UNNotificationContent: title, subtitle, body, userInfo, attachments و sound. يتم تطبيق التغييرات قبل عرض الإشعار.
فك تشفير المحتوى — إذا كان الإشعار الفوري يحتوي على حمولة مشفرة، تقوم الإضافة بفك تشفيرها قبل العرض. تنزيل الوسائط — إرفاق صورة أو فيديو بالإشعار. التوطين — تكييف نص الإشعار مع الإعدادات الإقليمية للجهاز. إثراء البيانات — إضافة معلومات إضافية من التخزين المحلي أو ذاكرة التخزين المؤقت.
وفقاً لـ Apple، السيناريو الأكثر شيوعاً بين التطبيقات هو تنزيل الصور للإشعارات الوسائطية الغنية. يرسل الخادم عنوان URL للصورة في الحمولة، وتقوم الإضافة بتنزيلها إلى دليل مؤقت وإنشاء 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 وإغلاق contentHandler الذي يجب استدعاؤه مع UNMutableNotificationContent المعدل. الإضافة ملزمة باستدعاء contentHandler — إذا لم تفعل، سيعرض iOS الإشعار الأصلي بعد انتهاء المهلة.
هام: يمكن للإضافة معالجة إشعار واحد فقط في كل مرة. إذا وصلت إشعارات متعددة في وقت واحد، ينشئ iOS مثيلات منفصلة للإضافة لكل منها. لا يمكن استخدام حالة عامة للمعالجة التسلسلية.
serviceExtensionTimeWillExpire() تُستدعى من قبل النظام عندما يوشك وقت التنفيذ المتبقي على الانتهاء. في هذه الطريقة، يجب استدعاء contentHandler فوراً مع أي محتوى جاهز في تلك اللحظة — حتى لو لم يكتمل تنزيل الملف الوسائطي. إذا لم يتم استدعاء contentHandler في هذه الطريقة، سيعرض iOS الإشعار الأصلي.
يوصى بحفظ محتوى مقبول بأقل درجة في هذه الطريقة — على سبيل المثال، إشعار بنص وعنوان ولكن بدون صورة لم يكتمل تنزيلها في الوقت المحدد.
UNNotificationAttachment هو كائن يتم إنشاؤه بواسطة الإضافة لإرفاق ملف وسائطي بالإشعار. تقوم الإضافة بتنزيل الملف من الشبكة، وحفظه في دليل مؤقت، وإنشاء UNNotificationAttachment مع تحديد نوع المحتوى.
يتم إنشاء UNNotificationAttachment باستخدام المُهيئ init(identifier:url:options:). يجب أن يشير URL إلى ملف محلي في الدليل المؤقت المتاح للإضافة. بعد الإنشاء، يتم إضافة المرفق إلى مصفوفة attachments الخاصة بـ UNMutableNotificationContent.
توصي Apple باستخدام URLSession مع تكوين خلفي للتنزيل — عند استخدام URLSession القياسي، يحجب التنزيل مؤشر التنفيذ ويستهلك وقتاً من حد الـ 30 ثانية. يستمر URLSession الخلفي في التنزيل حتى عند إنهاء الإضافة، ويمكن استخدام النتيجة عند التشغيل التالي.
إذا أرسل الخادم إشعاراً مشفراً، يجب على الإضافة فك تشفير الحمولة قبل استدعاء 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 خلال هذا الوقت، ينهي النظام العملية قسراً ويعرض الإشعار الأصلي دون تغيير.
يوصى بتنفيذ تراجع متعدد المستويات: محاولة تنزيل الوسائط أولاً، عند النجاح استدعاء contentHandler بالمحتوى الكامل؛ عند الفشل استدعاء contentHandler بالنص ولكن بدون وسائط؛ عند خطأ حرج تمرير المحتوى الأصلي. يضمن هذا النهج أن يرى المستخدم دائماً إشعاراً وليس شاشة فارغة.
وفقاً لـ Apple، السبب الأكثر شيوعاً للمهلات هو تنزيل ملفات وسائطية كبيرة عبر اتصال بطيء. لتقليل المخاطر، يوصى بتحسين حجم الصور على الخادم — إرسال معاينات حتى 300 كيلوبايت بدلاً من الدقة الكاملة. يجب تنزيل الصور كاملة الحجم عند فتح التطبيق.
لتتبع مهلات وأخطاء الإضافة، يمكن استخدام os_log لتسجيل رسائل التشخيص في نظام التسجيل الموحد. على الرغم من صعوبة التسجيل المباشر في ملف داخل الإضافة، يسمح 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 للإشعار الفوري. بدون هذا المعامل، يتجاهل النظام الإضافة ويعرض الإشعار القياسي.
لا. mutable-content:1 شرط إلزامي لتفعيل Service Extension. إذا كان المفتاح مفقوداً أو مضبوطاً على 0، يتم عرض الإشعار دون استدعاء الإضافة.
يقوم iOS بإنهاء الإضافة قسراً ويعرض الإشعار الأصلي دون تغيير. لتجنب ذلك، قم بتطبيق serviceExtensionTimeWillExpire() بمحتوى مقبول بأقل درجة.
عبر App Group (مشاركة UserDefaults أو ملف) أو Keychain مع وصول مشترك بين التطبيق والإضافة. تمرير المفاتيح مباشرة في حمولة الإشعار غير آمن.
حتى 4 مرفقات لكل إشعار، كل منها حتى 50 ميغابايت. يؤثر الحجم الإجمالي للمرفقات على وقت التنزيل — كلما زادت الملفات، زاد خطر المهلة.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا