You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何监听本地通知触发事件以在后台生成自定义重复通知?

解决本地通知触发后后台自动创建下一次通知的问题

你提到的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权限,让系统定期唤醒应用,检查是否需要补创建下一次通知:

  1. 首先在Info.plist中添加UIBackgroundModes,包含fetch项。
  2. 在AppDelegate/SceneDelegate中注册后台刷新:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 设置最小刷新间隔(系统会根据实际情况调整频率)
    UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
    return true
}
  1. 实现后台刷新的处理逻辑:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:33:13