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
相关产品推荐
相关产品推荐

