点击远程通知时,如何将视图控制器重置至根控制器(含UITabBar场景)?
嗨,这个需求我之前也帮别人实现过,其实逻辑很清晰,咱们一步步来搞定它!
实现步骤详解
1. 先拿到应用的根TabBar控制器
首先在你已经实现的userNotificationCenter(_:didReceive:withCompletionHandler:)方法里,得先获取到当前应用的根UITabBarViewController,这是操作所有Tab导航栈的基础。
如果你的项目是iOS13及以上(用了SceneDelegate),这么写:
guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = scene.windows.first, let tabBarController = window.rootViewController as? UITabBarViewController else { completionHandler() return }
要是还在兼容iOS12及以下,用这个更直接:
guard let tabBarController = UIApplication.shared.keyWindow?.rootViewController as? UITabBarViewController else { completionHandler() return }
2. 把最后一个Tab重置到根视图
接下来处理个人资料所在的最后一个Tab,要把它的导航栈完全清空回到根,同时关闭所有可能弹出的模态控制器:
// 取最后一个Tab的导航控制器 if let lastNavController = tabBarController.viewControllers?.last as? UINavigationController { // 先关闭所有模态弹出的页面 lastNavController.dismiss(animated: false) { // 把导航栈弹出到根视图 lastNavController.popToRootViewController(animated: false) } }
这里用animated: false是因为我们希望这个重置操作在后台完成,用户看不到这个过程,只需要最终的跳转结果就好。
3. 切换到消息Tab并跳转到目标聊天页
现在要切换到聊天页面所在的Tab(假设是第一个Tab,索引为0,你可以根据自己的Tab顺序调整),然后跳转到对应的聊天会话:
// 切换到消息Tab tabBarController.selectedIndex = 0 // 获取消息Tab的导航控制器 guard let chatNavController = tabBarController.viewControllers?[0] as? UINavigationController else { completionHandler() return } // 从推送的userInfo里取出聊天所需的参数(比如消息ID、对方ID) let userInfo = response.notification.request.content.userInfo let targetMessageId = userInfo["messageId"] as? String ?? "" // 创建聊天页面控制器(替换成你自己的聊天VC类) let chatVC = ChatViewController(messageId: targetMessageId) // 可选优化:检查聊天页是否已经在栈里,避免重复push if let existingChatVC = chatNavController.viewControllers.first(where: { $0 is ChatViewController && ($0 as? ChatViewController)?.messageId == targetMessageId }) { // 如果已经存在,直接跳转到该页面 chatNavController.popToViewController(existingChatVC, animated: true) } else { // 不存在的话就push新页面 chatNavController.pushViewController(chatVC, animated: true) }
完整的方法代码示例
把上面的步骤整合起来,就是你需要的完整实现:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { // 1. 获取根TabBar控制器 guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene, let window = scene.windows.first, let tabBarController = window.rootViewController as? UITabBarViewController else { completionHandler() return } // 2. 重置最后一个Tab到根视图 if let lastNavController = tabBarController.viewControllers?.last as? UINavigationController { lastNavController.dismiss(animated: false) { lastNavController.popToRootViewController(animated: false) } } // 3. 切换到消息Tab并跳转聊天页 tabBarController.selectedIndex = 0 guard let chatNavController = tabBarController.viewControllers?[0] as? UINavigationController else { completionHandler() return } let userInfo = response.notification.request.content.userInfo let targetMessageId = userInfo["messageId"] as? String ?? "" // 处理聊天页跳转逻辑 if let existingChatVC = chatNavController.viewControllers.first(where: { $0 is ChatViewController && ($0 as? ChatViewController)?.messageId == targetMessageId }) { chatNavController.popToViewController(existingChatVC, animated: true) } else { let chatVC = ChatViewController(messageId: targetMessageId) chatNavController.pushViewController(chatVC, animated: true) } // 一定要调用completionHandler completionHandler() }
几个额外的小提示
- 参数传递:确保推送的
userInfo里包含了足够的信息(比如消息ID、会话ID),这样才能精准跳转到对应的聊天页面。 - 动画控制:重置Tab的时候用无动画,跳转聊天页用有动画,这样用户体验更自然。
- 栈重复检查:上面的代码里加了检查聊天页是否存在的逻辑,避免用户重复进入同一个聊天会话,提升体验。
内容的提问来源于stack exchange,提问作者Florian Ldt
相关产品推荐
相关产品推荐

