本地通知内容深度解析 — 打造丰富的通知体验

本地通知内容深度解析 --- 打造丰富的通知体验

很多开发者在使用 UNMutableNotificationContent 时,往往只关注标题和正文,忽略了 Apple 提供的一系列定制化能力。本章将带你系统掌握这些能力,为你的通知赋予更多表现力和个性化。

本章将围绕 UNMutableNotificationContent 展开,详解它的各项配置能力,帮助你打造出兼具信息性与吸引力的通知内容。

一、是什么?

UNMutableNotificationContent 是 iOS 中配置本地通知内容的主要类,继承自 UNNotificationContent,用于设置标题、正文、声音、附件等视觉与听觉信息。示例:

ini 复制代码
 let content = UNMutableNotificationContent()
 content.title = "🔔 提醒"
 content.body = "你还有一项待完成的任务"
 content.sound = .default

二、常用属性

属性 类型 用途
title String 通知标题
subtitle String 子标题(在 title 下方展示)
body String 主内容,支持多行显示
badge NSNumber? 设置 App 图标的角标数字
sound UNNotificationSound? 通知音效
attachments [UNNotificationAttachment] 图像、音频或视频附件
categoryIdentifier String 配合交互动作使用
userInfo [AnyHashable: Any] 自定义字段,可用于跳转逻辑
threadIdentifier String 线程 ID,用于合并通知显示
interruptionLevel UNNotificationInterruptionLevel 设置通知优先级,影响通知的打断行为(如静默、时间敏感等)(iOS 15+)
relevanceScore Double 通知的相关性评分,系统用来决定通知的排序和优先级(iOS 15+)
filterCriteria String? 用于智能筛选通知,提高用户体验(iOS 16+)
targetContentIdentifier String? 帮助系统区分通知内容,实现更智能的展示和归类

三、通知声音:吸引注意

UNNotificationSound 是 iOS 推送通知系统中用于定义通知声音的类。

通知声音控制着通知触发时播放的声音,开发者可以使用系统默认声音,也可以指定自定义音频文件,甚至使用更特殊的"关键声音"(critical sound)来提高通知的优先级。

1. 普通通知声音

普通通知声音是最常见的通知提示音,使用系统默认音效,遵循系统音量和静音开关的控制。

方法名 作用 可用系统版本
UNNotificationSound.default 系统默认通知提示音 iOS 10.0+
init(named:) 使用自定义音频文件(放在 App Bundle) iOS 10.0+
说明
  • 这类声音不会绕过静音或勿扰模式。
  • 自定义声音需放在 App 主 Bundle,建议格式为 .caf.m4a.aiff,且时长不超过 30 秒。
  • 适用于普通提醒和非紧急通知。
示例
scss 复制代码
 // 系统默认声音
 content.sound = .default
 ​
 // 自定义声音
 content.sound = UNNotificationSound(named: UNNotificationSoundName("custom_sound.caf"))

2. 铃声类声音

铃声类声音类似电话铃声,声音更响亮且具有铃声特性,适合重要提示,但仍遵守系统静音规则。

方法名 作用 可用系统版本
ringtoneSoundNamed(_:) 返回指定名称的铃声声音 iOS 15.2+
说明
  • 该类型声音模拟来电铃声,提示效果明显。
  • 不绕过静音或勿扰模式。
  • 适合来电提醒或重要通知,增强用户注意力。
示例
ini 复制代码
 content.sound = UNNotificationSound.ringtoneSoundNamed(UNNotificationSoundName("ringtone.caf"))

3. 关键通知声音

关键通知声音拥有最高优先级,可以绕过静音和勿扰,确保用户接收到紧急通知,但需要用户授权。

方法名 作用 可用系统版本
defaultCritical 系统默认关键通知声音 iOS 12.0+
defaultCriticalSound(withAudioVolume:) 带自定义音量的关键通知默认声音 iOS 12.0+
criticalSoundNamed(_:) 返回指定名称的关键通知声音 iOS 12.0+
criticalSoundNamed(_:withAudioVolume:) 指定名称且带音量控制的关键通知声音 iOS 12.0+
使用关键声音的必要条件
  1. 主项目的info.plist中添加
xml 复制代码
 <key>UIBackgroundModes</key>
 <array>
    <string>critical-alert</string>
 </array>

📌 表示 App 申请使用关键通知能力,允许其在静音、勿扰等情况下播放声音。

  1. 授权中申请
javascript 复制代码
 UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge, .criticalAlert]) { granted, error in
    // granted 只是表示通知授权整体成功,不能单独判断 criticalAlert
 }
  1. 判断用户是否同意了权限
swift 复制代码
 UNUserNotificationCenter.current().getNotificationSettings { settings in
    switch settings.criticalAlertSetting {
    case .enabled:
        print("✅ 用户已开启关键通知")
    case .disabled:
        print("⚠️ 用户明确关闭了关键通知")
    case .notSupported:
        print("🚫 设备或系统不支持关键通知,或未通过审核")
    @unknown default:
        break
    }
 }
  1. 用户手动在设置中开启 允许关键通知 开关。
css 复制代码
设置 > 通知 > \[你的 App] > 允许关键通知 ✅ 此项必须由用户手动开启,App 无法直接引导跳转到该开关页(可跳转通知设置页,但不能直接定位到 critical 开关)。
  1. 允许关键通知 需要在 App Store 审核通过后才会出现。
说明
  • 关键通知声音绕过静音和勿扰模式,优先播放。
  • 需要用户在系统设置中开启"允许关键通知"权限。
  • 适用于医疗提醒、安全告警、重要紧急事件。
  • 音量可通过部分方法自定义。
  • 必须引导用户在「设置 > 通知 > 你的App > 允许关键通知」开启权限,否则关键通知声音无效。
  • 关键通知适用于确保用户感知的重要场景,不可滥用。
示例
ini 复制代码
 content.sound = UNNotificationSound.defaultCritical
 content.sound = UNNotificationSound.defaultCriticalSound(withAudioVolume: 0.8)
 content.sound = UNNotificationSound.criticalSoundNamed(UNNotificationSoundName("critical_alert.caf"))
 content.sound = UNNotificationSound.criticalSoundNamed(UNNotificationSoundName("critical_alert.caf"), withAudioVolume: 0.7)
授权流程
  1. App 需要向系统申请"关键通知"权限 这是单独于普通通知权限的高级权限,必须在系统设置里由用户手动允许,开发者无法弹窗直接请求,只能引导用户去设置里打开。
  2. 用户开启位置 用户打开「设置 > 通知 > 你的App > 允许关键通知」后,App 才能发送关键通知声音。
  3. 发送关键通知时,系统才会允许绕过静音和勿扰 未授权情况下,即使代码中设置了关键通知声音,也会被静音或不播放。

Apple 官方明确指出,以下几类应用可以申请 Critical Alerts 权限:

场景 示例
医疗相关 血糖监测、服药提醒、生命体征监控
安全监控 家庭安防、危险警告
公共安全 紧急预警、天气警报
时间提醒 闹钟、提醒事项、日程管理
无障碍辅助 听力障碍提醒、语音辅助等

使用自定义声音时注意

  • 音频文件必须放在 App 主 Bundle 内。

  • 建议文件时长不超过 30 秒。

  • 支持的格式通常为 .caf, .m4a, .wav, .aiff

  • 播放失败时,请确认:

    • 设备未处于静音模式或勿扰模式(对于普通通知声音)。
    • 应用已获得通知声音权限。
    • 文件存在且格式正确。

四、通知附件:让通知更具吸引力

attachments 是一个 [UNNotificationAttachment] 数组,支持加载本地的图片、音频、视频等文件作为通知的多媒体附件。

  • 这些资源必须先存储在设备本地的文件系统中,比如 app 的沙盒目录(Documentstmp 等)。

  • 不能直接传入 UIImage 或网络 URL,需要先把资源下载或复制到本地文件路径,然后用本地文件 URL 创建 UNNotificationAttachment

    swift 复制代码
     func downloadAndAttachImage(from url: URL, completion: @escaping (UNNotificationAttachment?) -> Void) {
        URLSession.shared.downloadTask(with: url) { localURL, response, error in
            guard let localURL = localURL else {
                completion(nil)
                return
            }
            do {
                let attachment = try UNNotificationAttachment(identifier: "remoteImage", url: localURL, options: nil)
                completion(attachment)
            } catch {
                print("创建附件失败:(error)")
                completion(nil)
            }
        }.resume()
     }
  • 虽然 attachments 支持添加多个附件,但在系统默认通知 UI 中通常只展示其中的一个(通常是第一个可支持展示的附件,如图片或视频)。若需展示多个附件,建议使用 Notification Content Extension 来实现自定义展示逻辑。

⚠️ 通知附件里的音频播放,是系统在通知中心的"小窗"里播放,系统会自动降低音量 ,确保不会突然打扰用户。所以即使你手机音量最大,通知附件的声音通常会比直接用 content.sound 播放的声音小很多。

4.1 添加图片附件

仅支持从主Bundle中,加载 PNG / JPEG / GIF / HEIC 类型的图片。

ini 复制代码
if let url = Bundle.main.url(forResource: "example", withExtension: "jpg") {
    let attachment = try? UNNotificationAttachment(identifier: "image", url: url)
    content.attachments = [attachment]
}

attachments 中加载 .xcassets里的图片 是无法直接加载的,因为:

.xcassets 中的资源在编译后会被打包进 Assets.car 文件中,并非文件系统中的独立文件,所以不能通过 URL 的方式直接访问。

可以使用 UIImage(named:) 加载 .xcassets 中的图片,将其转存为本地文件:

swift 复制代码
import UserNotifications
import UIKit

func createNotificationAttachment(fromImageNamed name: String, identifier: String = UUID().uuidString) -> UNNotificationAttachment? {
    guard let image = UIImage(named: name) else { return nil }

    // 将 UIImage 转为本地文件
    let fileManager = FileManager.default
    let tempDir = URL(fileURLWithPath: NSTemporaryDirectory())
    let fileURL = tempDir.appendingPathComponent("(UUID().uuidString).png")

    guard let imageData = image.pngData() else { return nil }

    do {
        try imageData.write(to: fileURL)
        let attachment = try UNNotificationAttachment(identifier: identifier, url: fileURL, options: nil)
        return attachment
    } catch {
        print("Attachment error: (error)")
        return nil
    }
}

4.2 添加音频或视频附件

ini 复制代码
if let url = Bundle.main.url(forResource: "earlyRiser", withExtension: "m4a") {
    let attachment = try? UNNotificationAttachment(identifier: "audio", url: url)
    content.attachments = [attachment].compactMap { $0 }
}
  • 支持:.m4a, .mp3, .caf,以及 .mov.mp4 等视频格式。
  • 附件音频在通知下拉后点击播放,但不会自动播放,需用户操作。
  • 实测音频作为附件时音量偏小,不如 sound 明显。

五、通知分组:整合内容

threadIdentifier 是 Apple 通知系统中用于将多个通知归为同一线程(thread)或对话(conversation) 的机制。用于"同类内容整合展示",避免通知中心杂乱。

如果你发送了 3 条通知,设置如下:

ini 复制代码
let content1 = UNMutableNotificationContent()
content1.title = "每日一句"
content1.body = "你若盛开,清风自来。"
content1.threadIdentifier = "daily_quotes"

let content2 = UNMutableNotificationContent()
content2.title = "每日一句"
content2.body = "生活明朗,万物可爱。"
content2.threadIdentifier = "daily_quotes"

let content3 = UNMutableNotificationContent()
content3.title = "突发提醒"
content3.body = "你有新的粉丝"
content3.threadIdentifier = "alerts"
  • 在通知中心里:

    • content1 和 content2 会被系统归入一组 "daily_quotes" 线程通知中
    • content3 则会单独显示,属于另一个线程。

想象成微信的聊天列表:每个 threadIdentifier 是一个"会话",多条通知属于同一个 thread。

六、自定义字段 userInfo

用于传递业务参数(如跳转页面的 ID):

css 复制代码
content.userInfo = ["taskId": "12345", "source": "reminder"]

App 在响应通知点击时可从 UNNotification.request.content.userInfo 中提取这些字段。

七、通知控制:场景使用

Apple 从 iOS 15 起引入了一些高级通知属性,主要用于优化通知在系统中的展示优先级与筛选逻辑,适用于关键通知、重要提醒、深度整合系统通知中心的场景。

属性 引入版本 用途
interruptionLevel iOS 15+ 控制通知的打断等级,如 .timeSensitive.critical
relevanceScore iOS 15+ 设置通知的相关性评分(0~1),系统会基于此排序展示优先级
filterCriteria iOS 16+ 通知筛选标识,系统可用于聚合筛选,结合通知摘要与聚类机制使用

interruptionLevel(打断等级)

设置通知对用户的「打断程度」

ini 复制代码
content.interruptionLevel = .active
等级 说明 适用场景
.passive 低打扰,仅出现在通知中心,不播放声音、不震动,不弹横幅 营销推广、新闻推送
.active 默认级别,正常展示横幅、声音 普通提醒任务、活动通知
.timeSensitive 时间敏感,可突破专注模式,在锁屏/静音下也能展示(需用户允许) 打卡、会议提醒、计时器到期
.critical 紧急通知,可突破勿扰模式和静音模式,需要苹果特别审核权限 生命健康相关(地震预警)

relevanceScore(相关性评分)

设置一个 0.0 ~ 1.0 的浮点值,表示通知相对于其他通知的重要程度。

ini 复制代码
content.relevanceScore = 0.8
系统行为:
  • 在锁屏或通知摘要中,系统会优先展示得分更高的通知。
  • 与通知内容是否置顶、合并展示的 threadIdentifier 无关,主要影响排序。
适用场景:
  • 多条通知同时弹出时,区分主次(如某条是系统状态,另一条是营销)
  • 电商 App:交易通知 > 广告通知
  • 消息类 App:@我 > 普通消息 > 群公告
注意事项:
  • 设置此属性 不会让通知"更容易展示" ,只是"被展示时排序更靠前"。
  • 需要结合 threadIdentifier 使用更有效(同类分组后排序)。

filterCriteria(筛选标识)

这个属性的用途更偏系统侧,用于系统级通知聚类、摘要和筛选机制。

主要用于与系统机制协同优化通知聚类,开发者无法直接操控其"可见效果"

ini 复制代码
content.filterCriteria = "payment_reminder"

小结:打造有质感的通知体验

一条通知的内容,远不止于"title + body"。通过对 UNMutableNotificationContent 的深入理解和运用,可以实现:

  • 图文并茂的提醒场景(如健康打卡、早起任务)
  • 音视频强化氛围(如冥想提示、生日祝福)
  • 更智能的行为追踪(通过 userInfo 联动页面)

在下一章中,我们将继续深入通知的交互机制,探索 UNUserNotificationCenterDelegate 如何让通知在前台弹出、支持交互按钮、跳转 App 内页面,真正从"发送一条通知"走向"打造一场互动"。

相关推荐
大熊猫侯佩1 小时前
探秘 WWDC 25 全新 #Playground 宏:提升 Swift 开发效率的超级神器
xcode·swift·wwdc
移动端小伙伴10 小时前
10.推送的扩展能力 — 打造安全的通知体验
swift
移动端小伙伴10 小时前
推送的扩展能力 — 打造个性化的通知体验
swift
移动端小伙伴10 小时前
远程推送(Remote Push Notification)
swift
移动端小伙伴11 小时前
本地通知的精准控制三角:时间、位置、情境
swift
移动端小伙伴11 小时前
通知交互设计全解:前台显示、按钮交互与用户行为响应
swift
移动端小伙伴11 小时前
本地通知的控制中枢 — 掌控调度与生命周期管理的关键
swift
移动端小伙伴11 小时前
通知权限获取的艺术 - 如何优雅地让用户说“好”
swift
杂雾无尘11 小时前
swift 基础:关联引用讲解
ios·swift·客户端