本地通知内容深度解析 --- 打造丰富的通知体验
很多开发者在使用 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+ |
使用关键声音的必要条件
- 主项目的info.plist中添加
xml
<key>UIBackgroundModes</key>
<array>
<string>critical-alert</string>
</array>
📌 表示 App 申请使用关键通知能力,允许其在静音、勿扰等情况下播放声音。
- 授权中申请
javascript
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge, .criticalAlert]) { granted, error in
// granted 只是表示通知授权整体成功,不能单独判断 criticalAlert
}
- 判断用户是否同意了权限
swift
UNUserNotificationCenter.current().getNotificationSettings { settings in
switch settings.criticalAlertSetting {
case .enabled:
print("✅ 用户已开启关键通知")
case .disabled:
print("⚠️ 用户明确关闭了关键通知")
case .notSupported:
print("🚫 设备或系统不支持关键通知,或未通过审核")
@unknown default:
break
}
}
- 用户手动在设置中开启 允许关键通知 开关。
css
设置 > 通知 > \[你的 App] > 允许关键通知 ✅ 此项必须由用户手动开启,App 无法直接引导跳转到该开关页(可跳转通知设置页,但不能直接定位到 critical 开关)。
- 允许关键通知 需要在 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)
授权流程
- App 需要向系统申请"关键通知"权限 这是单独于普通通知权限的高级权限,必须在系统设置里由用户手动允许,开发者无法弹窗直接请求,只能引导用户去设置里打开。
- 用户开启位置 用户打开「设置 > 通知 > 你的App > 允许关键通知」后,App 才能发送关键通知声音。
- 发送关键通知时,系统才会允许绕过静音和勿扰 未授权情况下,即使代码中设置了关键通知声音,也会被静音或不播放。
Apple 官方明确指出,以下几类应用可以申请 Critical Alerts 权限:
场景 | 示例 |
---|---|
医疗相关 | 血糖监测、服药提醒、生命体征监控 |
安全监控 | 家庭安防、危险警告 |
公共安全 | 紧急预警、天气警报 |
时间提醒 | 闹钟、提醒事项、日程管理 |
无障碍辅助 | 听力障碍提醒、语音辅助等 |
使用自定义声音时注意
-
音频文件必须放在 App 主 Bundle 内。
-
建议文件时长不超过 30 秒。
-
支持的格式通常为
.caf
,.m4a
,.wav
,.aiff
。 -
播放失败时,请确认:
- 设备未处于静音模式或勿扰模式(对于普通通知声音)。
- 应用已获得通知声音权限。
- 文件存在且格式正确。
四、通知附件:让通知更具吸引力
attachments
是一个 [UNNotificationAttachment]
数组,支持加载本地的图片、音频、视频等文件作为通知的多媒体附件。
-
这些资源必须先存储在设备本地的文件系统中,比如 app 的沙盒目录(
Documents
、tmp
等)。 -
不能直接传入 UIImage 或网络 URL,需要先把资源下载或复制到本地文件路径,然后用本地文件 URL 创建
UNNotificationAttachment
。swiftfunc 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 内页面,真正从"发送一条通知"走向"打造一场互动"。