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

Swift如何处理iOS14小组件到主应用的UserNotification通知

问题原因与解决方案

1. 现有代码缺失配置与错误点

  • 主应用侧没有在启动完成时主动设置UNUserNotificationCenter.current().delegate为AppDelegate/SceneDelegate的实例,仅实现代理方法不会自动生效,必须显式赋值。
  • 小组件中设置通知中心代理的操作完全无效:小组件的进程是临时的,仅在生成时间线时存活,任务完成后系统会立刻销毁进程,设置的delegate实例会随进程销毁而消失,不可能接收通知回调。
  • 当前发送的通知没有携带自定义标识参数,主应用收到点击事件后无法区分通知来源场景。

2. 双Target处理通知的方式错误点

  • 小组件侧不需要也不能实现UNUserNotificationCenterDelegate,所有通知的点击回调只会在启动的主应用进程中触发,小组件作为扩展没有常驻进程,根本不可能接收通知回调。
  • 主应用侧必须在application(_:didFinishLaunchingWithOptions:) 方法中第一时间设置通知中心的delegate,晚于系统触发通知回调的时机就会接收不到事件。

3. 正确实现步骤

第一步:移除小组件中所有和UNUserNotificationCenterDelegate相关的代码

小组件只负责调度通知,不需要处理回调,仅保留调度逻辑即可,同时可以在通知的userInfo中携带自定义参数,方便主应用识别来源:

// 小组件中仅保留调度通知逻辑,删除Delegate相关代码
func scheduleNotification(at date: Date, identifierUnic : String, body: String, titles:String) {
    UNUserNotificationCenter.current().removeAllPendingNotificationRequests()

    let triggerWeekly = Calendar.current.dateComponents([.day, .month, .hour,.minute, .year], from: date)
    let trigger = UNCalendarNotificationTrigger(dateMatching: triggerWeekly, repeats: true)
    let content = UNMutableNotificationContent()
    content.title = titles
    content.body = body
    content.sound = UNNotificationSound.default
    content.categoryIdentifier = "todoList2"
    // 新增:携带自定义参数,方便主应用识别是小组件触发的通知
    content.userInfo = ["source": "widget", "eventId": identifierUnic]
    
    let request = UNNotificationRequest(identifier: identifierUnic, content: content, trigger: trigger)
    UNUserNotificationCenter.current().add(request) {(error) in
        if let error = error {
            print(" We had an error: \(error)")
        }}
}

第二步:主应用侧正确配置通知代理

在AppDelegate的didFinishLaunchingWithOptions方法中显式设置代理:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 先请求通知权限(如果之前没请求的话)
    UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
        // 处理权限结果
    }
    // 核心:设置通知代理,必须在这个方法里执行,晚了会收不到冷启动时的通知点击事件
    UNUserNotificationCenter.current().delegate = self
    return true
}

// 实现代理方法,点击通知时一定会走这里
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    let userInfo = response.notification.request.content.userInfo
    print("userInfo \(userInfo)")
    // 可以根据userInfo里的source参数判断是不是小组件发来的通知,做对应逻辑
    if let source = userInfo["source"] as? String, source == "widget", let eventId = userInfo["eventId"] as? String {
        // 处理小组件通知的跳转逻辑,比如跳转到对应日历事件页面
    }
    completionHandler()
}

// 如果需要应用在前台时也显示通知,实现这个方法
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    completionHandler([.alert, .sound, .badge])
}

可选实现方式:通知Category自定义交互

如果需要给通知添加快捷操作,可以在主应用启动时注册通知Category,对应你设置的categoryIdentifier = "todoList2"即可。


内容的提问来源于stack exchange,提问作者Sukh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 11:45:10