点击推送打开APP后,如何在applicationWillEnterForeground获取通知对象?
解决iOS点击推送通知后获取通知对象并更新角标的问题
核心解决方案:使用UNUserNotificationCenterDelegate(iOS 10+)
不管应用处于后台、关闭还是前台状态,点击推送通知都会触发该代理的特定方法,能直接获取到通知对象,同时可以拦截系统自动跳转逻辑,先处理标记已读和角标更新。
1. 设置代理并请求通知权限
在AppDelegate的didFinishLaunchingWithOptions中添加:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 设置通知中心代理 UNUserNotificationCenter.current().delegate = self // 请求通知权限(按需调整权限类型) let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in // 处理权限申请结果 } return true }
2. 实现代理方法处理推送点击
扩展AppDelegate实现UNUserNotificationCenterDelegate:
extension AppDelegate: UNUserNotificationCenterDelegate { // 点击推送通知时触发(覆盖所有应用状态) func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { // 获取通知的用户信息和唯一标识 let userInfo = response.notification.request.content.userInfo let notificationId = response.notification.request.identifier // 步骤1:标记通知为已读(调用服务器API同步状态) markNotificationAsSeen(notificationId: notificationId) // 步骤2:更新应用角标计数(示例为减1,也可根据服务器返回的未读总数设置) if UIApplication.shared.applicationIconBadgeNumber > 0 { UIApplication.shared.applicationIconBadgeNumber -= 1 } else { UIApplication.shared.applicationIconBadgeNumber = 0 } // 步骤3:处理网页跳转(从自定义字段取URL,手动打开Safari,避免系统自动跳转跳过应用逻辑) if let customUrl = userInfo["custom_url"] as? String, let url = URL(string: customUrl) { UIApplication.shared.open(url) } // 必须调用完成回调 completionHandler() } // 可选:应用在前台时收到推送的展示逻辑 func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { completionHandler([.alert, .badge, .sound]) } // 模拟标记已读的服务器请求 private func markNotificationAsSeen(notificationId: String) { // 替换为你的实际网络请求代码,通知服务器该通知已被查看 print("标记通知 \(notificationId) 为已读") } }
3. 调整推送Payload格式
避免让系统自动处理跳转,把网页URL放在自定义字段中(不要用系统默认的跳转字段),示例Payload:
{ "aps": { "alert": "您有新消息", "badge": 1, "sound": "default" }, "custom_url": "https://example.com", "notification_id": "123456" }
为什么之前的方法无效?
applicationWillEnterForeground只能监听应用进入前台事件,但无法区分是用户主动打开还是点击推送打开,也拿不到具体的推送对象。application(_:didReceiveRemoteNotification:)在iOS 10后已被代理方法替代,且如果推送包含系统自动跳转的字段,系统会直接执行跳转,跳过该方法的触发。
iOS 9及以下兼容(可选)
如果需要兼容旧系统,可在AppDelegate中补充以下方法:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 应用从推送启动时获取通知信息 if let remoteNotification = launchOptions?[.remoteNotification] as? [AnyHashable: Any] { handlePushNotification(userInfo: remoteNotification) } return true } func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) { handlePushNotification(userInfo: userInfo) } private func handlePushNotification(userInfo: [AnyHashable: Any]) { // 这里重复标记已读、更新角标、处理跳转的逻辑 }
内容的提问来源于stack exchange,提问作者Marcel Kopera
相关产品推荐
相关产品推荐

