本地通知的精准控制三角:时间、位置、情境
本地通知无需依赖网络与服务端,触发精准、响应即时,是许多提醒类场景中更值得优先考虑的推送方式。
本章将围绕本地通知的三大触发机制------时间、位置、情境,帮助你打造"能如约而至、如影随形"的智能通知体系。
一、时间触发机制:定时通知的调度艺术
时间是通知最基本也是最常用的触发维度。iOS 提供了两种基于时间的触发器,分别适用于延迟执行 与定时调度场景,适合构建提醒类、日程类、打卡类通知体系。
类名 | 功能说明 |
---|---|
UNTimeIntervalNotificationTrigger |
延迟一段固定时间后触发 |
UNCalendarNotificationTrigger |
指定具体时间点或周期性日期触发通知 |
时间间隔触发器
10 秒后弹出一句每日提醒
ini
let content = UNMutableNotificationContent()
content.title = "📌 每日一句"
content.body = "每一个不曾起舞的日子,都是对生命的辜负"
content.sound = .default
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: false)
let request = UNNotificationRequest(identifier: "quote_001", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
日历间隔触发器
每天早上 8 点提醒用户打开学习 App
ini
var dateComponents = DateComponents()
dateComponents.hour = 8
dateComponents.minute = 0
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let content = UNMutableNotificationContent()
content.title = "🎓 今日计划"
content.body = "新的一天,来学习 30 分钟吧!"
content.sound = .default
let request = UNNotificationRequest(identifier: "quote_002", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
计算下一次触发时间
两种时间触发器都支持调用 nextTriggerDate()
方法,用于推算系统计划的下一次通知时间,非常适合用于:
- 调试:验证设置是否正确
- UI 展示:在界面上提示"将于明日 8:00 提醒"
- 时间校验:如用户设置的时间已过去,提示重新选择
swift
open func nextTriggerDate() -> Date?
如果设置合法,返回预计触发的 Date
,设置非法(如过去时间、无重复),返回 nil
。
使用说明与实践注意事项
1. 时间粒度限制
虽然可以设置为 10 秒后触发,但实际上:
- iOS 通知触发精度约为分钟级,不会做到秒级精准。
- 设置
timeInterval = 10
,系统可能在第 8~15 秒内任意时间触发。 - 目的是节省电量、合并唤醒操作。
📌 若对触发时效性要求极高,参考下文建议。
2. 循环触发约束
当 repeats = true
时,UNTimeIntervalNotificationTrigger
必须 ≥ 60 秒,否则系统会拒绝触发:
❌ 非法示例(不会触发):
php
UNTimeIntervalNotificationTrigger(timeInterval: 10, repeats: true)
补充说明:
如果你设置了 timeInterval = 10
且 repeats = true
,虽然这种配置不合法,系统仍会发送第一次通知 ,但不会重复触发后续通知
3. 触发时间不是严格保证的
- 系统不保证通知精确在预定时间触发,尤其是在后台、锁屏、低电量或系统调度繁忙时。
- iOS 的系统调度机制会结合:节能策略 、优先级、用户使用习惯、当前系统资源使用情况
- 系统会尝试在接近的合理时间窗口内发送通知,但存在几秒到几十秒的偏移。
📌 对于非常依赖时效(如闹钟、提醒类 App),建议配合:
interruptionLevel = .timeSensitive
relevanceScore
、后台任务、Local Push 与系统闹钟服务组合使用
4. iOS 16+ 特性提醒
- 在 iOS 16+ 中,系统对通知策略更加智能,可能根据用户习惯、通知类型、打断等级等进一步影响触发时机。
- 可以结合
interruptionLevel
和relevanceScore
进行优先级调整。
二、位置触发:打造"到此一游"的惊喜体验
本地通知不仅可以定时触发,也可以基于位置变化来"惊喜"推送。在用户进入或离开某个地理区域时触发通知,能很好地用于到店打卡、商圈提醒、景点互动等场景。
iOS 提供了 UNLocationNotificationTrigger
,结合 CLCircularRegion
可设置一个圆形的地理围栏,实现 "地理到达 / 离开"触发通知的能力。
示例:进入商圈后提醒"别忘了打卡"
ini
let center = CLLocationCoordinate2D(latitude: 31.2304, longitude: 121.4737) // 上海
let region = CLCircularRegion(center: center, radius: 200, identifier: "shanghai_center")
region.notifyOnEntry = true
region.notifyOnExit = false
let trigger = UNLocationNotificationTrigger(region: region, repeats: false)
let content = UNMutableNotificationContent()
content.title = "📍 欢迎来到上海商圈"
content.body = "别忘了到店打卡赢积分哦!"
content.sound = .default
let request = UNNotificationRequest(identifier: "location_checkin", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request)
⚠️ 地理围栏最大半径为 1000 米,最小建议设置为 100 米以上。
想实现"进入"和"离开"分别触发不同通知?
需要为进入和离开事件分别构造不同的通知内容和请求:
ini
// 创建共享的地理区域
let region = CLCircularRegion(center: center, radius: 200, identifier: "shanghai_center")
region.notifyOnEntry = true
region.notifyOnExit = true
// 进入区域通知
let enterContent = UNMutableNotificationContent()
enterContent.title = "📍 欢迎来到上海商圈"
enterContent.body = "别忘了到店打卡赢积分哦!"
enterContent.sound = .default
let enterTrigger = UNLocationNotificationTrigger(region: region, repeats: true)
let enterRequest = UNNotificationRequest(identifier: "enter_checkin", content: enterContent, trigger: enterTrigger)
UNUserNotificationCenter.current().add(enterRequest)
// 离开区域通知
let exitContent = UNMutableNotificationContent()
exitContent.title = "👋 回见!"
exitContent.body = "别忘了回顾你的打卡记录"
exitContent.sound = .default
let exitTrigger = UNLocationNotificationTrigger(region: region, repeats: true)
let exitRequest = UNNotificationRequest(identifier: "exit_checkin", content: exitContent, trigger: exitTrigger)
UNUserNotificationCenter.current().add(exitRequest)
虽然使用的是同一个 CLCircularRegion
对象,但只要 content
和 identifier
不同,系统就会在进入与离开时分别触发不同内容的通知。
理解位置触发的 repeats
UNLocationNotificationTrigger
的 repeats
参数,用于控制该位置通知是否可以反复触发:
值 | 行为说明 |
---|---|
false |
默认值 。通知仅触发一次。当用户首次进入或离开地理区域后,系统就会移除该触发器,后续再进入同一区域不会再次触发,除非你重新添加请求。 |
true |
每次进入或离开区域时,系统都会触发通知,适用于长期监控型的业务场景,如每日通勤、门店签到等。 |
注意点:
- 设置为
true
时,不需要重新注册通知请求,系统会持续监听该区域。 - 系统最多同时监控 20 个地理围栏 (由
CLLocationManager
限制),超出部分会被忽略,需合理规划。 - 由于通知内容写在
UNNotificationRequest
中,不能动态变化 ,如果你希望每次触发时展示不同内容,需要结合UNNotificationServiceExtension
实现动态内容替换。
注意事项
- 位置权限要求 :必须向用户请求定位权限,推荐使用
.requestAlwaysAuthorization()
,否则后台时无法触发通知。 - App 杀死时是否生效? :只要系统还在监控地理围栏,即使 App 未运行,通知依然会被触发。
- 省电策略影响:地理围栏的监控会受系统省电策略影响。系统会动态调节位置更新频率,特别在长时间静止或低电量时。
- 后台定位权限建议开启 :需在 Info.plist 中配置
NSLocationAlwaysAndWhenInUseUsageDescription
。
三、情境触发:结合后台任务精确送达
除了基于时间和位置的触发,本地通知还可以在特定后台任务完成时主动发送,这在文件下载、数据同步、缓存清理等场景特别实用。
iOS 通过 BGTaskScheduler
提供了后台任务调度功能,配合本地通知实现"任务完成立刻提醒"。
1. 任务注册 --- 在 App 启动时告诉系统你要执行哪些后台任务
在 AppDelegate
或启动流程中注册任务标识和对应处理函数:
php
import BackgroundTasks
BGTaskScheduler.shared.register(forTaskWithIdentifier: "com.myapp.cleanup", using: nil) { task in
self.handleCleanupTask(task: task as! BGProcessingTask)
}
2. 任务执行 --- 真正处理任务的地方
调度到后台时,系统会调用你注册的处理函数。这里你可以执行耗时任务,比如缓存清理:
scss
func handleCleanupTask(task: BGProcessingTask) {
// 任务到期时调用,确保任务能被及时终止
task.expirationHandler = {
// 取消或保存状态
}
// 异步执行清理操作,模拟耗时 2 秒
DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
// 任务完成后,发送本地通知
let content = UNMutableNotificationContent()
content.title = "🧹 清理完成"
content.body = "成功释放 240MB 空间"
content.sound = .default
// 立即发送通知,trigger 为 nil
let request = UNNotificationRequest(identifier: "cleanup_complete", content: content, trigger: nil)
UNUserNotificationCenter.current().add(request)
// 标记任务完成
task.setTaskCompleted(success: true)
}
}
3. 关键点说明
trigger: nil
表示通知立即发送,不依赖时间或位置触发。- 后台任务由系统调度,不保证立刻执行,可能延迟几分钟甚至更长时间,且有时不会被调度。
- 任务执行时长有限制(通常约 30 秒),需在
expirationHandler
中妥善处理超时。 BGProcessingTask
适合执行耗时且对时间要求不严的任务(如缓存清理、数据上传)。- 使用前需在项目
Info.plist
添加后台任务权限和任务标识。
4. 适用场景举例
- 清理缓存、释放空间
- 文件下载完成后提醒用户
- 同步或上传任务完成时通知
- 定期后台数据处理并提示结果
下一章预告:让通知更"有内容"
掌握了通知的精准触发时机,只是构建优秀通知体验的第一步。
真正能让用户点击、记住、感受到价值的通知,往往还依赖它的内容呈现力:
- ✍️ 图文并茂的通知样式
- 🔊 自定义音效营造氛围
- 🎬 音视频附件带来沉浸体验
- 🧠 配合分组、评分与打断等级,实现系统级调度优化
下一章《本地通知内容深度解析 --- 打造丰富的通知体验》,将带你深入探索 UNMutableNotificationContent
的每一项能力,帮助你打造更有温度、更有表现力的本地通知。