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

点击远程通知时,如何将视图控制器重置至根控制器(含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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 07:03:00