Notification Service Extension — یک افزونه iOS است که اعلان push را بلافاصله پس از دریافت، اما قبل از نمایش به کاربر رهگیری میکند. این افزونه میتواند payload رمزگذاریشده را رمزگشایی کند، فایل چندرسانهای را دانلود و ضمیمه کند، متن یا عنوان اعلان را در زمان واقعی تغییر دهد. طبق Apple Developer Documentation (2025)، برای فعالسازی افزونه، سرور باید کلید mutable-content:1 را در ویژگیهای اعلان ارسال کند — این تنها شرط راهاندازی UNNotificationServiceExtension است.
نکات اصلی
Notification Service Extension — یک app 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 ایجاد میکند که سیستم در رابط استاندارد یا سفارشی نمایش میدهد.
افزونه میتواند متن اعلان را کاملاً بازنویسی کند، عنوان را جایگزین یا subtitle اضافه کند. به عنوان مثال، یک برنامه پیامرسان میتواند اعلان رمزگذاریشده دریافت کند، آن را در افزونه رمزگشایی کند و متن قابل خواندن نمایش دهد. یا یک برنامه خبری میتواند دسته خبر را قبل از نمایش به زیرعنوان اضافه کند.
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 استاندارد، دانلود thread را مسدود کرده و زمان را از محدودیت 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 کیلوبایت به جای رزولوشن کامل ارسال کنید. تصاویر با رزولوشن کامل را بهتر است پس از باز کردن برنامه دانلود کنید.
برای ردیابی مهلتهای زمانی و خطاهای افزونه میتوان از 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 مگابایت. اندازه کل ضمیمهها بر زمان دانلود تأثیر میگذارد — هرچه فایلها بیشتر باشند، خطر مهلت زمانی بالاتر است.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید