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

如何在UNUserNotificationCenterDelegate中跳转至指定ViewController

在UNUserNotificationCenterDelegate中跳转指定ViewController的解决方案

我来帮你搞定这个问题!在UNUserNotificationCenterDelegate的回调里要跳转ViewController,核心是找到当前应用里最顶层的可交互视图控制器——直接拿根VC可能会遇到已经弹出其他页面的情况,导致跳转失效。下面给你两种靠谱的实现方式:

方法一:通过KeyWindow获取根VC快速展示

如果你的应用结构简单,没有多层弹出的弹窗或嵌套页面,可以直接用主窗口的根视图控制器来present目标VC:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    // 从故事板实例化目标VC
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    guard let targetVC = storyboard.instantiateViewController(withIdentifier: "beach") else {
        completionHandler()
        return
    }
    
    // 获取当前应用的主窗口
    guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else {
        completionHandler()
        return
    }
    
    // 从根VC展示目标VC
    keyWindow.rootViewController?.present(targetVC, animated: true, completion: nil)
    
    // 务必调用completionHandler,告诉系统处理完成
    completionHandler()
}

方法二:递归获取最顶层VC(适配复杂页面结构)

如果你的应用存在多层弹窗、导航栈嵌套或标签栏切换的情况,上面的方法可能会失效。推荐写一个UIViewController的扩展,递归找到当前最顶层的可展示VC:

extension UIViewController {
    /// 递归获取当前应用最顶层的视图控制器
    func topMostViewController() -> UIViewController {
        // 如果当前VC弹出了其他VC,继续递归查找
        if let presentedVC = presentedViewController {
            return presentedVC.topMostViewController()
        }
        
        // 如果是导航控制器,取当前可见的VC继续查找
        if let navVC = self as? UINavigationController {
            return navVC.visibleViewController?.topMostViewController() ?? self
        }
        
        // 如果是标签栏控制器,取选中的VC继续查找
        if let tabBarVC = self as? UITabBarController {
            return tabBarVC.selectedViewController?.topMostViewController() ?? self
        }
        
        // 最终返回最顶层的VC
        return self
    }
}

然后在Delegate回调里这样使用:

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    guard let targetVC = storyboard.instantiateViewController(withIdentifier: "beach") else {
        completionHandler()
        return
    }
    
    // 获取最顶层VC
    guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }),
          let topVC = keyWindow.rootViewController?.topMostViewController() else {
        completionHandler()
        return
    }
    
    // 根据需求选择跳转方式:push到导航栈 或 present弹窗
    if let navVC = topVC.navigationController ?? topVC as? UINavigationController {
        navVC.pushViewController(targetVC, animated: true)
    } else {
        topVC.present(targetVC, animated: true, completion: nil)
    }
    
    completionHandler()
}

关键提醒

  • 无论哪种方式,都必须在回调结束前调用completionHandler(),否则系统会判定你的处理超时。
  • 如果目标VC是导航流程的一部分,记得优先用pushViewController,避免多层弹窗的混乱体验。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 10:01:30