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

