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

点击推送打开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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 11:10:37