Notification Service Extension — نحوه پردازش اعلان‌ها

نویسنده: IT Sectr منتشر شده: 2026-06-16 زمان مطالعه: 9 دقیقه

Notification Service Extension — یک افزونه iOS است که اعلان push را بلافاصله پس از دریافت، اما قبل از نمایش به کاربر رهگیری می‌کند. این افزونه می‌تواند payload رمزگذاری‌شده را رمزگشایی کند، فایل چندرسانه‌ای را دانلود و ضمیمه کند، متن یا عنوان اعلان را در زمان واقعی تغییر دهد. طبق Apple Developer Documentation (2025)، برای فعال‌سازی افزونه، سرور باید کلید mutable-content:1 را در ویژگی‌های اعلان ارسال کند — این تنها شرط راه‌اندازی UNNotificationServiceExtension است.

نکات اصلی

  • Notification Service Extension اعلان push را قبل از نمایش به کاربر در دستگاه iOS تغییر می‌دهد
  • برای فعال‌سازی افزونه، پارامتر mutable-content:1 در payload اعلان از سرور مورد نیاز است
  • پروتکل اصلی — UNNotificationServiceExtension با متدهای didReceive(_:withContentHandler:) و serviceExtensionTimeWillExpire()
  • افزونه می‌تواند ضمیمه‌های چندرسانه‌ای را از شبکه دانلود کرده و از طریق UNNotificationAttachment به اعلان ضمیمه کند
  • زمان اجرا محدود است — سیستم حدود 30 ثانیه برای پردازش کامل یک اعلان اختصاص می‌دهد

Notification Service Extension چیست

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 اصلی را به آن منتقل می‌کند و منتظر نسخه تغییر یافته برای نمایش می‌ماند.

پردازش اعلان‌های push در لحظه

UNNotificationServiceExtension UNNotificationRequest کامل را با محتوای اصلی دریافت می‌کند. افزونه می‌تواند هر فیلد UNNotificationContent را تغییر دهد: title, subtitle, body, userInfo, attachments و sound. تغییرات قبل از نمایش اعلان اعمال می‌شوند.

سناریوهای معمول استفاده

رمزگشایی محتوا — اگر اعلان push حاوی payload رمزگذاری‌شده باشد، افزونه آن را قبل از نمایش رمزگشایی می‌کند. دانلود رسانه — ضمیمه کردن تصویر یا ویدیو به اعلان. بومی‌سازی — تطبیق متن اعلان با تنظیمات منطقه‌ای دستگاه. غنی‌سازی داده‌ها — افزودن اطلاعات اضافی از حافظه محلی یا کش.

طبق Apple، رایج‌ترین سناریو در میان برنامه‌ها دانلود تصاویر برای اعلان‌های چندرسانه‌ای غنی است. سرور URL تصویر را در payload ارسال می‌کند، افزونه آن را در دایرکتوری موقت دانلود کرده و UNNotificationAttachment ایجاد می‌کند که سیستم در رابط استاندارد یا سفارشی نمایش می‌دهد.

تغییر متن و عنوان

افزونه می‌تواند متن اعلان را کاملاً بازنویسی کند، عنوان را جایگزین یا subtitle اضافه کند. به عنوان مثال، یک برنامه پیام‌رسان می‌تواند اعلان رمزگذاری‌شده دریافت کند، آن را در افزونه رمزگشایی کند و متن قابل خواندن نمایش دهد. یا یک برنامه خبری می‌تواند دسته خبر را قبل از نمایش به زیرعنوان اضافه کند.

swift
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

UNNotificationServiceExtension — کلاس پایه‌ای که Service Extension از آن ارث‌بری می‌کند. این کلاس دو متد چرخه حیات را تعریف می‌کند: didReceive(_:withContentHandler:) — متد اصلی پردازش، و serviceExtensionTimeWillExpire() — مدیریت‌کننده اتمام زمان.

متد didReceive:withContentHandler:

didReceive(_:withContentHandler:) هنگام دریافت اعلان فراخوانی می‌شود. افزونه UNNotificationRequest و closure contentHandler را دریافت می‌کند که باید با UNMutableNotificationContent تغییر یافته فراخوانی شود. افزونه موظف است contentHandler را فراخوانی کند — اگر این کار را نکند، iOS پس از اتمام مهلت، اعلان اصلی را نمایش می‌دهد.

مهم: افزونه می‌تواند فقط یک اعلان را در یک زمان پردازش کند. اگر چند اعلان به طور همزمان برسند، iOS نمونه‌های جداگانه‌ای از افزونه برای هر کدام ایجاد می‌کند. نمی‌توان از حالت جهانی برای پردازش ترتیبی استفاده کرد.

متد serviceExtensionTimeWillExpire:

serviceExtensionTimeWillExpire() توسط سیستم فراخوانی می‌شود وقتی زمان اجرای باقی‌مانده رو به اتمام است. در این متد باید فوراً contentHandler را با محتوایی که در حال حاضر آماده است فراخوانی کنید — حتی اگر فایل چندرسانه‌ای هنوز دانلود نشده باشد. اگر contentHandler در این متد فراخوانی نشود، iOS اعلان اصلی را نمایش خواهد داد.

توصیه می‌شود در این متد حداقل محتوای قابل قبول را ذخیره کنید — به عنوان مثال، اعلان با متن و عنوان، اما بدون تصویری که دانلود آن به موقع کامل نشده است.

رمزگذاری و ضمیمه‌های چندرسانه‌ای

UNNotificationAttachment — شیئی که توسط افزونه برای ضمیمه کردن فایل چندرسانه‌ای به اعلان ایجاد می‌شود. افزونه فایل را از شبکه دانلود می‌کند، آن را در دایرکتوری موقت ذخیره می‌کند و UNNotificationAttachment با مشخص کردن نوع محتوا ایجاد می‌کند.

ایجاد ضمیمه از فایل دانلود شده

UNNotificationAttachment با استفاده از مقداردهنده init(identifier:url:options:) ایجاد می‌شود. URL باید به یک فایل محلی در دایرکتوری موقت قابل دسترس برای افزونه اشاره کند. پس از ایجاد، ضمیمه به آرایه attachments در UNMutableNotificationContent اضافه می‌شود.

Apple استفاده از URLSession با پیکربندی پس‌زمینه را برای دانلود توصیه می‌کند — با استفاده از URLSession استاندارد، دانلود thread را مسدود کرده و زمان را از محدودیت 30 ثانیه مصرف می‌کند. URLSession پس‌زمینه حتی پس از پایان افزونه به دانلود ادامه می‌دهد و نتیجه می‌تواند در راه‌اندازی بعدی استفاده شود.

رمزگشایی payload رمزگذاری‌شده

اگر سرور اعلان رمزگذاری‌شده ارسال کند، افزونه باید payload را قبل از فراخوانی contentHandler رمزگشایی کند. رمزگشایی معمولاً شامل درخواست کلید از Keychain یا App Group، رمزگشایی از طریق CommonCrypto و جایگزینی body یا userInfo اعلان است. در صورت خطای رمزگشایی، باید contentHandler را با محتوای اصلی فراخوانی کرد — تا کاربر حداقل ببیند که اعلان رسیده است، حتی اگر ناخوانا باشد.

swift
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()
}

مهلت زمانی و مکانیزم‌های fallback

Notification Service Extension در چارچوب زمانی محدودی کار می‌کند. iOS زمان ثابتی برای اجرا اختصاص می‌دهد — حدود 30 ثانیه از لحظه فعال‌سازی. اگر افزونه در این مدت contentHandler را فراخوانی نکند، سیستم فرآیند را به اجبار خاتمه داده و اعلان اصلی را بدون تغییر نمایش می‌دهد.

استراتژی graceful degradation

توصیه می‌شود fallback چندسطحی پیاده‌سازی شود: ابتدا سعی کنید رسانه را دانلود کنید، در صورت موفقیت — contentHandler را با محتوای کامل فراخوانی کنید؛ در صورت شکست — contentHandler را با متن اما بدون رسانه فراخوانی کنید؛ در صورت خطای بحرانی — محتوای اصلی را منتقل کنید. این رویکرد تضمین می‌کند که کاربر همیشه یک اعلان می‌بیند، نه یک صفحه خالی.

طبق Apple، شایع‌ترین دلیل مهلت‌های زمانی دانلود فایل‌های چندرسانه‌ای بزرگ در اتصال کند است. برای کاهش خطر، توصیه می‌شود اندازه تصاویر را در سرور بهینه کنید — پیش‌نمایش تا 300 کیلوبایت به جای رزولوشن کامل ارسال کنید. تصاویر با رزولوشن کامل را بهتر است پس از باز کردن برنامه دانلود کنید.

نظارت بر عملکرد

برای ردیابی مهلت‌های زمانی و خطاهای افزونه می‌توان از os_log برای نوشتن پیام‌های تشخیصی در Unified Logging System استفاده کرد. اگرچه ثبت مستقیم در فایل در افزونه دشوار است، os_log امکان تحلیل عملکرد را از طریق Console.app در دستگاه توسعه‌دهنده فراهم می‌کند. Apple توصیه می‌کند برای هر فراخوانی didReceive معیارهایی اضافه کنید — زمان دانلود، اندازه فایل، نتیجه عملیات.

swift
override func serviceExtensionTimeWillExpire() {
    let fallback = bestEffortContent as?
        UNMutableNotificationContent
        ?? request.content.mutableCopy()
        as! UNMutableNotificationContent
    contentHandler(fallback)
}

سوالات متداول

سرور چگونه Notification Service Extension را فعال می‌کند؟

سرور کلید mutable-content:1 را به دیکشنری aps اعلان push اضافه می‌کند. بدون این پارامتر، سیستم افزونه را نادیده گرفته و اعلان استاندارد را نمایش می‌دهد.

آیا می‌توان از افزونه بدون mutable-content استفاده کرد؟

خیر. mutable-content:1 شرط اجباری فعال‌سازی Service Extension است. اگر کلید وجود نداشته باشد یا روی 0 تنظیم شده باشد، اعلان بدون فراخوانی افزونه نمایش داده می‌شود.

پس از تجاوز از محدودیت 30 ثانیه چه اتفاقی می‌افتد؟

iOS به اجبار افزونه را خاتمه داده و اعلان اصلی را بدون تغییر نمایش می‌دهد. برای جلوگیری از این، serviceExtensionTimeWillExpire() را با حداقل محتوای قابل قبول پیاده‌سازی کنید.

چگونه کلیدهای رمزگذاری را به افزونه منتقل کنیم؟

از طریق App Group (UserDefaults یا فایل مشترک) یا Keychain با دسترسی مشترک بین برنامه و افزونه. انتقال مستقیم کلیدها در payload اعلان ناامن است.

چند فایل چندرسانه‌ای می‌توان در Service Extension ضمیمه کرد؟

تا 4 ضمیمه برای هر اعلان، هر یک تا 50 مگابایت. اندازه کل ضمیمه‌ها بر زمان دانلود تأثیر می‌گذارد — هرچه فایل‌ها بیشتر باشند، خطر مهلت زمانی بالاتر است.

خلاصه

  • Notification Service Extension اعلان‌های push را در دستگاه قبل از نمایش تغییر می‌دهد، متن، عنوان و ضمیمه‌های چندرسانه‌ای را ویرایش می‌کند
  • برای فعال‌سازی کلید mutable-content:1 در دیکشنری aps مورد نیاز است — بدون آن افزونه راه‌اندازی نمی‌شود
  • پروتکل اصلی UNNotificationServiceExtension متدهای didReceive و serviceExtensionTimeWillExpire را برای پردازش تعریف می‌کند
  • افزونه می‌تواند رسانه را از شبکه دانلود کند، payload را رمزگشایی کند و تا 4 ضمیمه به اعلان اضافه کند
  • زمان اجرا به حدود 30 ثانیه محدود است — در صورت تجاوز، iOS اعلان اصلی را نمایش می‌دهد
  • استراتژی graceful degradation با fallback چندسطحی برای جلوگیری از اعلان‌های خالی توصیه می‌شود

ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد

IT Sectr از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید