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

App关闭时推送通知行为异常的技术咨询

解决iOS点击远程通知(含Deep Link)在App关闭状态下异常的问题

哥们,我之前踩过一模一样的坑!你现在遇到的问题核心原因很明确:当App处于完全关闭(冷启动)状态时,点击远程通知启动App,不会触发你写的那两个didReceiveRemoteNotification方法,而是会走App启动的入口方法application(_:didFinishLaunchingWithOptions:)(iOS 12及以下)或者SceneDelegate的scene(_:willConnectTo:options:)(iOS 13+)。

下面给你一套完整的解决方案,覆盖所有场景:

第一步:抽离公共的通知处理逻辑

先把你原来在didReceiveRemoteNotification里处理Deep Link的代码,抽成一个独立的私有方法,这样不管是冷启动还是后台唤醒,都复用同一套逻辑,避免重复代码和不一致的问题:

private func handleRemoteNotification(userInfo: [AnyHashable: Any]) {
    // 这里放你原来处理Deep Link的核心逻辑
    // 示例:从userInfo里提取Deep Link URL并跳转
    guard let deepLinkString = userInfo["deep_link"] as? String,
          let deepLinkUrl = URL(string: deepLinkString) else {
        return
    }
    
    // 注意:冷启动时App UI可能未完全初始化,直接跳转可能出问题
    // 这里可以根据情况处理:比如暂存URL,等App就绪后再跳转
    if UIApplication.shared.applicationState == .active {
        // App在前台,直接跳转
        navigateToDeepLink(url: deepLinkUrl)
    } else {
        // App从后台或冷启动,暂存URL,等主界面加载完成后跳转
        UserDefaults.standard.set(deepLinkString, forKey: "PendingDeepLink")
        // 可以通过NotificationCenter发送通知,通知主控制器处理跳转
        NotificationCenter.default.post(name: NSNotification.Name("HandlePendingDeepLink"), object: nil)
    }
}

// 示例:跳转逻辑(根据你的App路由方式调整)
private func navigateToDeepLink(url: URL) {
    // 比如用UIApplication打开,或者用你自己的路由框架
    UIApplication.shared.open(url, options: [:], completionHandler: nil)
}

第二步:适配冷启动场景

iOS 12及以下(AppDelegate)

在application(_:didFinishLaunchingWithOptions:)里检查是否是通过远程通知启动的,是的话调用公共处理方法:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 检查启动参数里的远程通知
    if let remoteNotification = launchOptions?[.remoteNotification] as? [AnyHashable: Any] {
        handleRemoteNotification(userInfo: remoteNotification)
    }
    
    // 其他初始化代码...
    
    // 检查是否有暂存的Deep Link,App就绪后处理
    if let pendingDeepLink = UserDefaults.standard.string(forKey: "PendingDeepLink"),
       let url = URL(string: pendingDeepLink) {
        navigateToDeepLink(url: url)
        UserDefaults.standard.removeObject(forKey: "PendingDeepLink")
    }
    
    return true
}

iOS 13+(SceneDelegate)

如果你的App适配了多场景,还要在SceneDelegate里处理冷启动的通知:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // 检查是否是远程通知启动
    if let remoteNotification = connectionOptions.remoteNotification {
        handleRemoteNotification(userInfo: remoteNotification.userInfo)
    }
    
    // 其他初始化代码...
}

// 后台唤醒时的通知处理
func scene(_ scene: UIScene, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    handleRemoteNotification(userInfo: userInfo)
    completionHandler(.newData) // 根据实际处理结果返回对应的状态
}

// 场景激活时处理暂存的Deep Link
func sceneDidBecomeActive(_ scene: UIScene) {
    if let pendingDeepLink = UserDefaults.standard.string(forKey: "PendingDeepLink"),
       let url = URL(string: pendingDeepLink) {
        navigateToDeepLink(url: url)
        UserDefaults.standard.removeObject(forKey: "PendingDeepLink")
    }
}

第三步:改造原有的通知处理方法

把原来的两个didReceiveRemoteNotification方法改成调用公共函数,同时别忘了处理fetchCompletionHandler:

// iOS 10以下的前台/后台通知处理
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]) {
    handleRemoteNotification(userInfo: userInfo)
}

// 带后台刷新的通知处理
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    handleRemoteNotification(userInfo: userInfo)
    // 根据你的处理结果返回对应的状态:.newData/.noData/.failed
    completionHandler(.newData)
}

关键注意点

  • 冷启动的UI就绪问题:冷启动时App的ViewController可能还没加载完成,直接跳转会导致崩溃或无响应,所以建议暂存Deep Link,等App的主界面激活后再处理(比如在sceneDidBecomeActive或主控制器的viewDidAppear里)。
  • iOS版本适配:如果你的App同时支持iOS 12及以下和iOS 13+,要同时处理AppDelegate和SceneDelegate的逻辑,避免遗漏场景。
  • completionHandler的调用:带fetchCompletionHandler的方法必须调用这个闭包,否则会影响App的后台刷新权限。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:39:49