如何监听本地通知触发事件以在后台生成自定义重复通知?
解决本地通知触发后后台自动创建下一次通知的问题
你提到的didReceive代理方法确实有局限性——它要么在应用前台收到通知时触发,要么在用户点击通知(无论应用是前台/后台/未运行)时触发。如果应用在后台挂起甚至没启动,且用户没点击通知,iOS不会主动唤醒应用执行代码。下面分场景给你可行的解决方案:
1. 用户点击通知时(覆盖所有应用状态)
只要用户点击了通知,不管当前应用是前台、后台还是刚被唤醒,都可以在userNotificationCenter(_:didReceive:withCompletionHandler:)方法里计算并创建下一次通知。这是最可靠的触发时机:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { // 先拿到当前触发通知的相关信息(可选,比如用来计算下一次时间的参数) let triggerInfo = response.notification.request.content.userInfo // 替换成你的自定义计算逻辑,比如根据上次触发时间算出下一次的时间点 guard let nextTriggerDate = calculateNextNotificationDate(lastTriggerDate: Date()) else { completionHandler() return } // 构建新的通知内容 let content = UNMutableNotificationContent() content.title = "重复提醒" content.body = "这是根据上一次触发计算出的新通知" content.sound = .default content.userInfo = ["lastTriggerTime": Date().timeIntervalSince1970] // 可以存标识方便后续处理 // 创建日历触发器(按你需要的时间点触发) let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: nextTriggerDate) let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false) // 生成唯一标识符的通知请求 let request = UNNotificationRequest( identifier: UUID().uuidString, content: content, trigger: trigger ) // 添加通知到系统 UNUserNotificationCenter.current().add(request) { error in if let error = error { print("创建下一次通知失败: \(error.localizedDescription)") } } // 必须调用完成处理器 completionHandler() }
2. 应用前台运行时,通知触发但用户没点击
这种情况用willPresent代理方法,它会在前台收到通知时立即触发,你可以在这里同步创建下一次通知:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { // 先设置前台展示通知的方式(比如横幅+声音) completionHandler([.banner, .sound]) // 同样的逻辑计算并创建下一次通知 guard let nextTriggerDate = calculateNextNotificationDate(lastTriggerDate: Date()) else { return } let content = UNMutableNotificationContent() content.title = "重复提醒" content.body = "前台触发后生成的新通知" content.sound = .default let dateComponents = Calendar.current.dateComponents([.hour, .minute], from: nextTriggerDate) let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false) let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) { error in if let error = error { print("前台创建通知失败: \(error.localizedDescription)") } } }
3. 应用后台挂起/未运行,用户未点击通知
这种情况iOS不会唤醒你的应用,所以没法实时触发代码。可以用两个补救方案:
方案A:后台定期刷新检查
开启Background App Refresh权限,让系统定期唤醒应用,检查是否需要补创建下一次通知:
- 首先在
Info.plist中添加UIBackgroundModes,包含fetch项。 - 在AppDelegate/SceneDelegate中注册后台刷新:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 设置最小刷新间隔(系统会根据实际情况调整频率) UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum) return true }
- 实现后台刷新的处理逻辑:
func application(_ application: UIApplication, performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { // 获取当前所有待触发的通知 UNUserNotificationCenter.current().getPendingNotificationRequests { existingRequests in // 自定义判断逻辑:比如检查是否存在下一个时间点的通知,没有就创建 let needCreateNext = self.shouldGenerateNextNotification(existingRequests: existingRequests) if needCreateNext { guard let nextTriggerDate = self.calculateNextNotificationDate(lastTriggerDate: Date()) else { completionHandler(.failed) return } // 重复之前的通知创建逻辑 let content = UNMutableNotificationContent() content.title = "后台刷新提醒" content.body = "系统后台刷新时补创建的通知" content.sound = .default let dateComponents = Calendar.current.dateComponents([.hour, .minute], from: nextTriggerDate) let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false) let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger) UNUserNotificationCenter.current().add(request) { error in completionHandler(error == nil ? .newData : .failed) } } else { completionHandler(.noData) } } }
方案B:应用启动时补创建
在应用每次启动(包括从后台唤醒到前台)时,检查是否需要补创建遗漏的通知:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 检查并补创建通知 checkAndCreateMissingNotifications() return true } func sceneWillEnterForeground(_ scene: UIScene) { // 应用从后台回到前台时也检查一次 checkAndCreateMissingNotifications() } private func checkAndCreateMissingNotifications() { UNUserNotificationCenter.current().getPendingNotificationRequests { existingRequests in if self.shouldGenerateNextNotification(existingRequests: existingRequests) { // 创建下一次通知的逻辑同上 } } }
关键注意事项
- 确保已申请本地通知权限:在应用启动时请求
alert、sound等权限,没有权限的话通知无法创建和展示。 - 通知标识符要唯一,避免重复添加;如果需要替换已有的待触发通知,可以先调用
removePendingNotificationRequests(withIdentifiers:)移除旧的再添加新的。 - 后台刷新的频率由系统控制,无法保证精确触发,所以它只能作为补充方案,核心还是依赖用户点击通知和前台触发的场景。
内容的提问来源于stack exchange,提问作者Kosrat D. Ahmad
相关产品推荐
相关产品推荐

