Notification Extension:核心概念、扩展类型和配置

作者: IT Sectr 发布日期: 2026-03-20 阅读时间: 8 分钟

Notification Extension 是 iOS 的一种机制,允许在向用户显示推送通知之前修改其内容和外观。扩展在操作系统端以独立进程运行:UNNotificationServiceExtension 处理传入内容,而 UNNotificationContentExtension 管理界面。根据 Apple Developer Documentation, 2026Service Extension 在通知显示前有最多 30 秒来执行任务。这个限制在加载附件或解密数据时至关重要。

要点

  • Service Extension — 在显示前拦截通知,允许修改文本、添加媒体和解密数据,限制 30 秒。
  • Content Extension — 通过 storyboard 或 SwiftUI 创建具有自定义 UI、按钮和触摸处理的通知自定义界面。
  • 媒体附件 — 图像、视频和音频通过 UNNotificationAttachment 在 Service Extension 中添加,然后传递给 Content Extension。
  • 注册 — 两个扩展都在 Info.plist 中作为独立 target 注册,指定通知类别和 NSExtensionPointIdentifier。
  • 限制 — 扩展无法访问主应用程序,在隔离的沙盒中运行,内存限制为 50 MB。

什么是 Notification Extension

Notification Extension 是 iOS 的一个软件组件,它扩展了推送通知的标准行为,增加了修改内容和自定义界面的能力。与系统以标准形式显示的普通通知不同,扩展允许开发者在显示前影响内容,并创建独特的用户界面。

两种通知扩展类型

Apple 为不同目的提供两种 Notification Extension:UNNotificationServiceExtension 负责处理传入的 payload,而 UNNotificationContentExtension 管理显示。Service Extension 在通知显示前启动,根据 Apple Developer Documentation 有有限的执行时间 — 最多 30 秒。Content Extension 在用户与通知交互后激活,并显示自定义视图。

与标准通知的区别

标准 iOS 推送通知由系统根据 JSON-payload 中的 alert、title 和 subtitle 字段自动显示。Notification Extension 接管控制权:Service Extension 接收原始 payload,对其进行修改,然后传递给系统显示。Content Extension 用带有任意控制元素的自定义界面替换标准横幅。

扩展的生命周期

当设备收到带有 mutable-content: 1 键的推送通知时,系统在独立进程中启动 Service Extension。扩展进程与主应用程序隔离,并拥有自己的沙盒,内存限制为 50 MB。处理完成后,扩展调用 completion handler,将修改后的 UNNotificationContent 传递给系统显示。

UNNotificationServiceExtension:内容修改

UNNotificationServiceExtension 是在推送通知显示给用户之前以编程方式修改它们的主要工具。当收到 payload 中设置了 mutable-content: 1 标志的通知时,扩展会自动激活。在 30 秒内,扩展可以加载媒体附件、修改文本、解密加密数据或丰富内容。

UNNotificationServiceExtension 协议的方法

扩展实现了 UNNotificationServiceExtension 协议中的两个关键方法。didReceive 方法接收带有原始 UNNotificationRequest 的传入请求,并允许通过带有新 UNNotificationContent 的 completion handler 进行修改。serviceExtensionTimeWillExpire 方法在超时前 1 秒由系统调用 — 在此方法中需要完成处理并传递当前(可能部分)结果。

示例:向通知添加图像

考虑服务器在自定义字段中发送带有图像 URL 的推送的场景。Service Extension 通过网络加载此图像,创建 UNNotificationAttachment 并将其添加到内容中。UNNotificationAttachment 接受本地图像、视频或音频文件,并自动将其复制到扩展的沙盒中。创建附件后,扩展将更新后的内容传递给系统。

swift
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:自定义界面

UNNotificationContentExtension 允许用 Interface Builder 或 SwiftUI 中创建的自定义界面替换标准通知横幅。当用户对通知执行操作时扩展被激活:触摸、向下滑动或 3D Touch。Content Extension 接收已经由 Service Extension 处理的内容,并在自定义视图中显示。

Storyboard 和通知类别

每个 Content Extension 通过 Info.plist 绑定到一个或多个通知类别。类别由服务器在 APNS payload 中用 category 字段确定。系统根据接收到的通知类别自动选择正确的扩展。界面通过 storyboard 使用标准 UIKit 组件或 SwiftUI View 构建。

处理用户操作

Content Extension 支持在 UNNotificationAction 中定义的自定义按钮和触摸处理。UNNotificationAction 在类别注册阶段创建,可以通过 UNTextInputNotificationAction 进行文本输入。当用户按下按钮时,扩展收到带有操作标识符的 didReceive 回调,并可以执行相应的逻辑 — 打开 URL、向服务器发送请求或更新界面。

性能限制

Content Extension 在隔离进程中运行,拥有自己的执行循环和约 50 MB 的内存限制。扩展的性能至关重要,因为系统 watchdog 会在超出限制时终止进程。建议避免在 Content Extension 内进行繁重计算、加载大图像和长时间网络请求。

媒体附件和 UNNotificationAttachment

UNNotificationAttachment 是向推送通知添加媒体文件的对象:图像、视频、音频或 GIF。附件从必须位于扩展沙盒中的本地文件 URL 创建。附件的最大大小不得超过 10 MB,否则系统将在创建时拒绝附件。

支持的格式

Apple 支持有限的一组媒体附件格式。图像 — JPEG、PNG、GIF(包括动画)、TIFF。视频 — MPEG、MP4、MOV,最大时长 30 秒。音频 — MP3、AAC、WAV、CAF。对于每种格式,可以通过 UNNotificationAttachmentOptionsTypeHintKey 指定类型,这有助于系统正确处理文件。

从网络加载附件

由于推送 payload 只包含 URL 而不是文件本身,附件的加载必须在 Service Extension 内部完成。最大加载时间限制为 30 秒,因此建议使用带有最小设置的 URLSession,并在信号弱时禁用加载。如果附件未及时加载,通知将不显示媒体 — 这是系统的默认行为。

Swift 实现示例

让我们看一个完整的 Notification Extension 示例,它加载图像、下载并将其添加到通知中。NotificationService 继承自 UNNotificationServiceExtension 并重写 didReceive 方法。示例展示了可选字段的处理、附件的创建以及使用修改后内容调用 completion handler。

swift
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

为了扩展的正确运行,需要在 Info.plist 中注册通知类别。NSExtensionPointIdentifier 键对于 Service Extension 设置为 com.apple.usernotifications.service,对于 Content Extension 设置为 com.apple.usernotifications.content。类别在 AppDelegate 中应用程序启动时通过 UNUserNotificationCenter 定义,扩展仅对 payload 中具有相应类别的通知激活。

常见问题

Service Extension 和 Content Extension 有什么区别?

Service Extension 在通知显示前修改内容 — 添加媒体、更改文本、解密数据。Content Extension 在用户交互后用自定义界面替换通知界面。Service Extension 在显示前工作,Content Extension — 之后。

Service Extension 中有多少处理时间?

系统分配 30 秒用于在 didReceive 中执行代码。如果处理未在此时间内完成,将调用 serviceExtensionTimeWillExpire,需要在此传递当前结果。建议在考虑附件加载的情况下在 10-15 秒内完成。

可以在 Content Extension 中使用 SwiftUI 吗?

是的,从 iOS 16 开始,SwiftUI 在 Content Extension 中得到支持。View 被包装在 UIHostingController 中并添加到 storyboard。然而,由于内存限制,建议仅对具有最少元素数量的简单界面使用 SwiftUI。

如何处理附件加载错误?

在加载错误或超过时间限制时,只需使用不带附件的原始内容调用 completion handler。系统将以标准形式显示通知,不带媒体。通过 OSLog 记录错误以进行诊断,但不要阻止通知的显示。

Notification Extension 的内存限制是什么?

扩展在隔离进程中运行,限制约为 50 MB。超出限制时,系统通过 watchdog 终止进程。避免加载大文件、在内存中存储图像以及在使用 URLSession 时出现内存泄漏。

总结

  • Notification Extension — iOS 用于修改推送通知的机制,包括 Service Extension(内容)和 Content Extension(界面)。
  • Service Extension 在通知显示前处理 payload,限制 30 秒,可以添加媒体附件和解密数据。
  • Content Extension 通过 UIKit 或 SwiftUI 替换标准横幅为自定义界面,支持交互式按钮。
  • UNNotificationAttachment 向通知添加图像、视频和音频,支持 JPEG、PNG、MP4、MP3 等格式。
  • 扩展注册 通过 Info.plist 完成,指定 NSExtensionPointIdentifier 和用于激活的通知类别。
  • 限制 — 50 MB 内存限制、无法访问主应用程序的隔离沙盒、有限的执行时间。
  • Notification Extension 是创建丰富用户通知的关键工具,可提高 iOS 中推送通信的参与度和功能性。

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读