Notification Service Extension: چیست، پردازش محتوا قبل از نمایش در iOS

نویسنده: IT Sectr منتشر شده: 2026-03-21 زمان مطالعه: 8 دقیقه

Notification Service Extension — یک افزونه iOS است که اعلان push را قبل از نمایش به کاربر intercept می‌کند و اجازه تغییر محتوا را می‌دهد. این افزونه می‌تواند داده‌های رمزگذاری‌شده را رمزگشایی کند، پیوست‌های رسانه‌ای را دانلود کند، متن را تغییر دهد یا فیلدهای سفارشی اضافه کند. به گفته Apple Developer, 2025, Notification Service Extension تا 30 ثانیه برای انجام وظیفه در پس‌زمینه فرصت دارد.

اصلی

  • Notification Service Extension — افزونه iOS برای پردازش اعلان push قبل از نمایش.
  • افزونه از UNNotificationServiceExtension ارث‌بری می‌کند و متد didReceive را پیاده‌سازی می‌کند.
  • تا 30 ثانیه زمان پردازش پس‌زمینه برای دانلود و پردازش داده‌ها در دسترس است.
  • سناریوهای اصلی: رمزگشایی payload، دانلود تصاویر و ویدئو، اعتبارسنجی محتوا.
  • افزونه می‌تواند نمایش اعلان را به تأخیر بیندازد یا کاملاً از طریق contentHandler آن را لغو کند.

Notification Service Extension چیست

Notification Service Extension — یک app extension در iOS است که قبل از نمایش اعلان push اجرا می‌شود. این امکان را می‌دهد که سرور payload حداقلی ارسال کند و افزونه آن را با محتوا تکمیل کند: تصاویر را دانلود کند، داده‌ها را رمزگشایی کند، متن را جایگزین کند. کاربر اعلان آماده و پردازش‌شده را می‌بیند.

چگونه کار می‌کند

وقتی iOS یک اعلان push دریافت می‌کند، سیستم وجود افزونه را برای آن برنامه بررسی می‌کند. اگر افزونه ثبت شده باشد، iOS آن را در یک فرآیند پس‌زمینه اجرا می‌کند و محتوای اعلان را از طریق متد didReceive(_:withContentHandler:) ارسال می‌کند. افزونه محتوا را پردازش می‌کند و contentHandler را با محتوای تغییر یافته فراخوانی می‌کند. اگر افزونه در 30 ثانیه موفق نشود، سیستم اعلان اصلی را نمایش می‌دهد.

چه زمانی از Service Extension استفاده کنیم

Service Extension در سناریوهایی ضروری است که محتوای اعلان نیاز به پردازش روی دستگاه دارد. ارتباطات امن: سرور payload رمزگذاری‌شده ارسال می‌کند، افزونه آن را محلی رمزگشایی می‌کند. اعلان‌های رسانه‌ای غنی: سرور URL تصویر را ارسال می‌کند، افزونه آن را دانلود و ضمیمه می‌کند. بومی‌سازی پویا: افزونه متن را به زبان دستگاه تنظیم می‌کند.

سناریوبدون افزونهبا افزونه
تصویرپشتیبانی نمی‌شوددانلود و نمایش داده می‌شود
رمزگذاریسرور کلید را نگه می‌داردرمزگشایی روی دستگاه
متنثابت روی سرور تنظیم شدهجایگزینی پویا
اعتبارسنجیبررسی نمی‌شودلغو اعلان‌های مخرب

محدودیت‌ها و زمان اجرا

Notification Service Extension در یک محیط محدود کار می‌کند. حداکثر زمان اجرا — 30 ثانیه. افزونه به حافظه اصلی برنامه (به جز App Group) دسترسی ندارد. اندازه افزونه به 50 مگابایت محدود است. در صورت تجاوز از زمان، سیستم contentHandler را با محتوای اصلی فراخوانی می‌کند و تمام تغییرات از دست می‌روند.

ایجاد افزونه و تنظیم Info.plist

در Xcode Notification Service Extension از طریق ایجاد target جدید از نوع Notification Service Extension اضافه می‌شود. Xcode یک الگوی کلاس NotificationService ایجاد می‌کند که از UNNotificationServiceExtension ارث‌بری می‌کند و دو متد دارد: didReceive و serviceExtensionTimeWillExpire.

افزودن target به پروژه

در Xcode گزینه File → New → Target → Notification Service Extension را انتخاب کنید. نام (مثلاً PushNotificationService) و زبان Swift را مشخص کنید. مطمئن شوید که target به برنامه اصلی اضافه شده و امضای درستی دارد. پس از ایجاد، کلاس NotificationService.swift با پیاده‌سازی پایه تولید می‌شود.

ساختار Info.plist افزونه

Info.plist افزونه شامل کلید NSExtension با کلیدهای فرعی NSExtensionPointIdentifier (com.apple.usernotifications.service) و NSExtensionPrincipalClass (نام کنترلر شما) است. به صورت اختیاری می‌توان NSExtensionAttributes را با قوانین فعال‌سازی افزونه مشخص کرد. این تنظیمات توسط Xcode به صورت خودکار تولید می‌شوند.

نمونه افزونه پایه

پیاده‌سازی پایه didReceive را بازنویسی می‌کند، محتوای اعلان را تغییر می‌دهد و contentHandler را فراخوانی می‌کند. اگر پردازش زمان زیادی ببرد، serviceExtensionTimeWillExpire فراخوانی می‌شود که در آن باید کار را با وضعیت فعلی به پایان برسانید.

swift
import UserNotifications

class NotificationService: UNNotificationServiceExtension {

    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?

    override func didReceive(
        request: UNNotificationRequest,
        withContentHandler handler: @escaping (UNNotificationContent) -> Void
    ) {
        contentHandler = handler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

        if let bestAttemptContent = bestAttemptContent {
            bestAttemptContent.title = "[پردازش شد] \(bestAttemptContent.title)"
            contentHandler?(bestAttemptContent)
        }
    }

    override func serviceExtensionTimeWillExpire() {
        if let contentHandler = contentHandler,
           let bestAttemptContent = bestAttemptContent {
            contentHandler(bestAttemptContent)
        }
    }
}

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

یکی از کاربردهای کلیدی Service Extension رمزگشایی محتوای اعلان روی دستگاه است. سرور payload رمزگذاری‌شده ارسال می‌کند و افزونه آن را با استفاده از کلیدی که در Keychain یا App Group ذخیره شده رمزگشایی می‌کند. این تضمین می‌کند که محتوا در هنگام انتقال قابل intercept نیست.

معماری تحویل امن

سرور بدنه اعلان را با استفاده از یک کلید متقارن (AES-256) رمزگذاری می‌کند. کلید رمزگذاری از قبل بین کلاینت و سرور توافق می‌شود. افزونه رشته رمزگذاری‌شده را در فیلد data payload دریافت می‌کند، آن را رمزگشایی می‌کند و در فیلدهای اعلان قرار می‌دهد. کلید کاربر می‌تواند پس از احراز هویت از Keychain دریافت شود.

swift
override func didReceive(
    request: UNNotificationRequest,
    withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
    guard let content = request.content.mutableCopy()
        as? UNMutableNotificationContent else {
        handler(request.content)
        return
    }

    guard let encryptedData = content.userInfo["encrypted_data"]
        as? String else {
        handler(content)
        return
    }

    let decrypted = CryptoService.decrypt(encryptedData)
    content.body = decrypted.body
    content.title = decrypted.title
    handler(content)
}

ذخیره امن کلیدها

کلید رمزگشایی نباید در کد افزونه یا NSUserDefaults ذخیره شود. از iOS Keychain با دسترسی از طریق App Group استفاده کنید تا هم برنامه و هم افزونه بتوانند کلید را بخوانند. برای تولید کلید در سمت کلاینت از Security.framework با الگوریتم AES-256-GCM استفاده کنید.

دانلود و ضمیمه‌کردن پیوست‌های رسانه‌ای

رایج‌ترین کاربرد Notification Service Extension — دانلود تصاویر، GIF و ویدئو برای نمایش بعدی در اعلان است. سرور URL فایل رسانه‌ای را ارسال می‌کند و افزونه آن را دانلود کرده، در دایرکتوری موقت ذخیره می‌کند و UNNotificationAttachment ایجاد می‌کند.

فرآیند دانلود و ضمیمه‌کردن رسانه

افزونه URL تصویر را از فیلد payload اعلان دریافت می‌کند. با استفاده از URLSession، افزونه فایل را به دایرکتوری موقت دانلود می‌کند. پس از اتمام دانلود، UNNotificationAttachment با URL محلی ایجاد می‌شود. پیوست به محتوای تغییر یافته منتقل می‌شود. iOS به طور خودکار تصویر را در رابط استاندارد یا در Notification Content Extension نمایش می‌دهد.

swift
private func downloadAndAttachMedia(
    content: UNMutableNotificationContent,
    mediaUrl: String,
    handler: @escaping (UNNotificationContent) -> Void
) {
    guard let url = URL(string: mediaUrl) else {
        handler(content)
        return
    }

    let task = URLSession.shared.downloadTask(with: url) { localUrl, _, error in
        guard let localUrl = localUrl, error == nil else {
            handler(content)
            return
        }

        let attachment = try? UNNotificationAttachment(
            identifier: "media",
            url: localUrl,
            options: nil
        )

        if let attachment = attachment {
            content.attachments = [attachment]
        }
        handler(content)
    }
    task.resume()
}

فرمت‌های رسانه‌ای پشتیبانی‌شده

iOS از فرمت‌های زیر برای نمایش در اعلان‌ها پشتیبانی می‌کند: JPEG، PNG، GIF (ایستا)، ویدئو MPEG-4 تا 50 مگابایت. برای فایل‌های صوتی MP3، AAC و ALAC پشتیبانی می‌شوند. مهم: تمام فایل‌های رسانه‌ای باید در محدوده 30 ثانیه دانلود شوند. برای فایل‌های بزرگ، برش سمت سرور یا دانلود تدریجی توصیه می‌شود.

مدیریت زمان و سناریوهای بازگشتی

مدیریت محدودیت 30 ثانیه‌ای — وظیفه کلیدی در توسعه Notification Service Extension است. اگر افزونه پردازش را کامل نکند، سیستم serviceExtensionTimeWillExpire را فراخوانی کرده و محتوای اصلی را نمایش می‌دهد. باید سناریوهای بازگشتی برای هر نوع پردازش پیش‌بینی شود.

استراتژی اولویت‌ها

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

بازگشت در خطاها

اگر دانلود تصویر ناموفق بود یا رمزگشایی payload خطا برگرداند، افزونه باید contentHandler را با محتوای اصلی فراخوانی کند. هرگز افزونه را بدون فراخوانی contentHandler پایان ندهید — این باعث از دست رفتن اعلان می‌شود. بازگشت امن همیشه باید در کد افزونه پیش‌بینی شود.

swift
override func didReceive(
    request: UNNotificationRequest,
    withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
    let content = (request.content.mutableCopy()
        as? UNMutableNotificationContent) ?? request.content

    // وظیفه حیاتی: رمزگشایی
    var decryptedContent = tryDecryptPayload(content)

    // وظیفه اختیاری: رسانه
    guard let mediaUrl = decryptedContent.userInfo["media_url"]
        as? String else {
        handler(decryptedContent)
        return
    }

    downloadAndAttachMedia(
        content: decryptedContent,
        mediaUrl: mediaUrl,
        handler: handler
    )
}

تست افزونه

برای تست Notification Service Extension از Xcode استفاده کنید: target افزونه را انتخاب کنید، روی شبیه‌ساز اجرا کنید و یک اعلان push از طریق ترمینال یا Firebase Console ارسال کنید. هر مرحله پردازش را از طریق os_log لاگ کنید — این به تشخیص مشکلات زمان‌بندی و خطاهای بارگذاری کمک می‌کند.

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

اگر افزونه در 30 ثانیه موفق نشود چه اتفاقی می‌افتد؟

سیستم serviceExtensionTimeWillExpire را فراخوانی می‌کند و سپس اعلان اصلی را بدون تغییر نمایش می‌دهد. تمام فایل‌های دانلود شده و تغییرات حذف می‌شوند.

آیا می‌توان نمایش اعلان را از افزونه لغو کرد؟

بله، اگر contentHandler را با محتوای خالی (UNNotificationContent با فیلدهای خالی) فراخوانی کنید، اعلان نمایش داده نمی‌شود. این برای فیلتر کردن اعلان‌های اسپم یا داده‌های نادرست استفاده می‌شود.

چگونه توکن احراز هویت را برای دانلود رسانه ارسال کنیم؟

توکن را می‌توان در userInfo payload اعلان ارسال کرد یا از Keychain از طریق App Group دریافت کرد. ذخیره توکن‌ها در UserDefaults افزونه توصیه نمی‌شود.

آیا پیکربندی خاصی برای گواهی‌های افزونه لازم است؟

افزونه باید با همان گواهی توسعه‌دهنده برنامه اصلی امضا شود. برای تولید به گواهی تولید با قابلیت Push Notifications فعال نیاز است.

چگونه افزونه را روی دستگاه واقعی اشکال‌زدایی کنیم؟

دستگاه را به Xcode متصل کنید، target افزونه را در طرح راه‌اندازی انتخاب کنید و یک اعلان push از طریق Firebase Console ارسال کنید. Breakpoints در افزونه مانند برنامه اصلی کار می‌کنند.

خلاصه

  • Notification Service Extension — افزونه iOS برای پردازش پس‌زمینه اعلان‌های push قبل از نمایش.
  • حداکثر زمان اجرا — 30 ثانیه، پس از آن سیستم محتوای اصلی را نمایش می‌دهد.
  • کاربردهای اصلی: رمزگشایی payload، دانلود رسانه، اعتبارسنجی و بومی‌سازی محتوا.
  • افزونه از UNNotificationServiceExtension با متدهای didReceive و serviceExtensionTimeWillExpire ارث‌بری می‌کند.
  • برای دانلود رسانه از URLSession، برای ذخیره کلیدها از iOS Keychain استفاده کنید.
  • همیشه بازگشت را پیش‌بینی کنید — در صورت خطا contentHandler را با محتوای اصلی فراخوانی کنید.
  • Service Extension را با Content Extension برای کنترل کامل بر اعلان‌ها ترکیب کنید.

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

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

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

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