Router — iOS 和 Android 中的路由模式基础

作者: IT Sectr 发布日期: 2026-02-19 阅读时间: 9 分钟

Router — 一种架构模式,集中管理应用程序屏幕之间的导航逻辑。Router 决定事件发生时导航到哪里以及如何导航。在 iOS 中,Router 抽象了 UINavigationController 和 segue,在 Android 中 — FragmentManager 和 Jetpack Navigation 的 NavController。Router 可以作为独立模式运行,也可以作为 Coordinator(Router-per-Coordinator)和 VIPER(Router-per-module)的组件。更多信息 — 参见 Android Navigation Component Guide

要点

  • Router — 集中管理屏幕间导航的路由模式
  • 两个层次 — Router 可以是 Coordinator 的组件或独立模式
  • iOS Router — 对 UINavigationController 的抽象,提供 push/present/pop 方法
  • Android Router — 带有 NavController 和 deep links 的 Jetpack Navigation Component
  • URL Routing — 基于 URL 方案的路由(deeplink、universal link)

什么是 Router:路由模式的本质

Router — 封装屏幕间转换逻辑的模式。核心理念:ViewController(或 Presenter/ViewModel)不直接调用 navigationController.pushViewController,而是通知 Router 其导航意图。Router 决定创建哪个 ViewController 以及如何显示它。Router 可以简单(一组导航方法)或复杂(基于 URL 方案、deep link 和推送通知的路由)。

三种 Router 方法 — Router 作为服务(全局 Navigator 单例)、Router 作为模块组件(VIPER 方法)、Router 作为协议(Coordinator 的抽象)。全局 Router — 简单性(每个应用程序一个实例)— 在小型项目中流行。模块化 Router — 每个功能都有自己的 Router — VIPER 和 Clean Architecture 的标准。协议化 Router — 用于 Coordinator:带有 push/present/pop/dismiss 方法的 RouterProtocol。

方法结构使用时机
全局 Navigator带有转换方法的单例小型项目、原型
模块化 Router每个模块内部的 RouterVIPER、Clean Architecture
协议化 Router协议 + Coordinator 的实现MVVM-C、Coordinator 模式

模式历史 — Router 出现在 Web 框架中(URL Router — Rails Routes、Express.js),并被适配用于移动开发。在 iOS 中,Router 随着 VIPER 的兴起(2015-2017)而流行。在 Android 中,Router 是 Jetpack Navigation(2018)的一部分,这是 Google 的导航标准解决方案。现在 Router 是每个模块化移动应用架构不可或缺的一部分。

iOS 中的 Router:Swift 实现

iOS Router — 包含不同类型导航方法的协议。基本实现包装了 UINavigationController。Router 可以管理模态呈现(present/dismiss)、导航栈中的 push/pop、Split View Controller 的 showDetail 以及全屏呈现(iOS 13+)。Router 不创建 ViewController — 它接收一个准备好的实例并显示它。ViewController 的创建由工厂(Assembly、DI 容器)或 Coordinator 完成。

swift
// 针对 iOS 的 RouterProtocol
protocol RouterProtocol {
    func push(_ viewController: UIViewController, animated: Bool)
    func pop(animated: Bool)
    func popToRoot(animated: Bool)
    func present(_ viewController: UIViewController, animated: Bool)
    func dismiss(animated: Bool)
    func setViewControllers(_: [UIViewController], animated: Bool)
}

// 通过 UINavigationController 实现 Router
class NavigationRouter: RouterProtocol {
    private let navigationController: UINavigationController

    init(navigationController: UINavigationController) {
        self.navigationController = navigationController
    }

    func push(_ vc: UIViewController, animated: Bool) {
        if navigationController.presentedViewController {
            navigationController.dismiss(animated: false)
        }
        navigationController.pushViewController(vc, animated: animated)
    }

    func pop(animated: Bool) {
        navigationController.popViewController(animated: animated)
    }

    func popToRoot(animated: Bool) {
        navigationController.popToRootViewController(animated: animated)
    }

    func present(_ vc: UIViewController, animated: Bool) {
        navigationController.present(vc, animated: animated)
    }

    func dismiss(animated: Bool) {
        navigationController.dismiss(animated: animated)
    }

    func setViewControllers(_ vcs: [UIViewController], animated: Bool) {
        navigationController.setViewControllers(vcs, animated: animated)
    }
}

// Assembly — 创建带 Router 的模块
protocol ProfileModuleFactory {
    func makeProfileView() -> UIViewController
}

VIPER 中的 Router — 每个 VIPER 模块都有自己的 Router,知道应从当前模块打开哪些屏幕。Router 通过工厂创建下一个模块的 ViewController 并转移控制权。VIPER 中的 Router — 唯一包含 import UIKit 的组件(除了 View)。这简化了 Presenter 和 Interactor 的测试:它们不依赖于 UIKit。

Android 中的 Router:Jetpack Navigation Component

Jetpack Navigation Component — Android 的标准路由器,自 2018 年起由 Google 推荐。导航在 XML 图(nav_graph.xml)中定义:节点(fragments、activities、destinations)和边(actions)。NavController 管理转换:调用 FragmentManager.replace/add 并管理返回栈。Navigation Component 支持 deep link、参数、转换动画以及 Safe Args 实现类型安全的数据传输。

kotlin
// nav_graph.xml — 导航图
<!-- @xml/nav_graph.xml -->
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/loginFragment">

    <fragment android:id="@+id/loginFragment"
        android:name=".ui.login.LoginFragment">
        <action android:id="@+id/to_home"
            app:destination="@id/homeFragment" />
    </fragment>

    <fragment android:id="@+id/homeFragment"
        android:name=".ui.home.HomeFragment">
        <argument android:name="userId"
            android:defaultValue="0"
            app:argType="integer" />
        <deepLink app:uri="myapp://home/{userId}" />
    </fragment>
</navigation>

// Kotlin — 通过 NavController 导航
class LoginFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.loginButton.setOnClickListener {
            val action = LoginFragmentDirections.toHome(userId = 42)
            findNavController().navigate(action)
        }
    }
}

// Safe Args — 类型安全参数
class HomeFragmentArgs : NavArgs {
    val userId: Int get() = arguments?.getInt("userId") ?: 0
}

// NavigationUI — 与 Toolbar、BottomNav、Drawer 的集成
class MainActivity : AppCompatActivity() {
    private lateinit var navController: NavController

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val navHost = supportFragmentManager
            .findFragmentById(R.id.nav_host_fragment) as NavHostFragment
        navController = navHost.navController
        NavigationUI.setupActionBarWithNavController(this, navController)
    }
}

Android Navigation 中的 Deep Links — Navigation Component 支持显式 deep link(PendingIntent + NavDeepLinkBuilder)和隐式 deep link(通过清单中的 intent-filter)。Deep link 可以指向 nav_graph 中的任何节点。推送通知的处理:Notification 使用 NavDeepLinkBuilder 创建 PendingIntent,恢复返回栈并打开所需屏幕。Navigation Component 自动处理 Up/Back 按钮并将用户返回到上一个屏幕。

URL Routing:Deeplink 和 Universal Link 路由

URL Routing — 基于 URL 方案、deep link 和 universal link 的路由。应用程序注册一个方案(myapp://profile/42)或 universal link(https://example.com/profile/42)。Router 解析 URL,提取参数(userId=42)并打开相应的屏幕。URL Routing 允许从外部打开应用程序:通过网站链接、电子邮件、推送通知、二维码。iOS 使用 NSUserActivity + universal link,Android — intent-filter + deep link。

swift
// URL Router — 解析 deep link 和导航
protocol URLRoute {
    var pattern: String { get }
    func navigate(parameters: [String: String], router: RouterProtocol)
}

struct ProfileRoute: URLRoute {
    let pattern = "myapp://profile/{userId}"

    func navigate(parameters: [String: String], router: RouterProtocol) {
        guard let userId = parameters["userId"] else { return }
        let profileVC = ProfileViewController(userId: userId)
        router.push(profileVC, animated: true)
    }
}

// URL Router — 将 URL 映射到路由
class URLRouter {
    private var routes: [URLRoute] = []

    func handle(_ url: URL, router: RouterProtocol) {
        for route in routes {
            if let params = matchPattern(route.pattern, url: url) {
                route.navigate(parameters: params, router: router)
                return
            }
        }
    }
}

Deep link 路由实践 — 应用程序必须在三种状态下处理 deep link:未启动(通过 deep link 启动)、后台(从后台恢复)、活跃(onNewIntent/SceneDelegate)。URL Router 必须正确恢复返回栈:当 deep link 到个人资料屏幕时,用户应该能够按 Back 并返回到上一个屏幕。iOS 和 Android 对返回栈的处理不同 — Router 必须考虑平台特性。

Router 与 Coordinator 和 Navigator 的比较

Router vs Coordinator — Router 回答“如何显示屏幕?”(push/present),Coordinator — “显示哪个屏幕?”(启动哪个流程)。Router — 导航工具,Coordinator — 流程组织者。Router 由 Coordinator 使用。在 VIPER 中,Router 执行两种功能:决定导航到哪里以及如何显示。在 MVVM-C 中,Router 是 Coordinator 使用的独立协议。这些模式并不互斥,而是相互补充。

特性RouterCoordinatorNavigator
焦点导航机制导航流程全局访问
层级UI 框架(push/present)业务逻辑(流程)基础设施
屏幕创建接收准备好的 VC通过工厂创建 VC创建 VC
生命周期每个导航一个childCoordinators单例

Router vs Navigator — Navigator 是 iOS 社区中 Router 的旧称。在早期实现中,Navigator 是一个带有转换方法的单例类。Navigator 是全局的 Router 单例。Navigator 更简单,但会产生隐藏的依赖关系。基于协议的 Router 更可测试且更模块化。Navigator 适用于没有严格架构的项目,Router 适用于 Clean Architecture 和 VIPER。

常见问题

Router 和 Coordinator 有什么区别?

Router — 对 UINavigationController 的抽象(push/present/pop)。Coordinator — Router 之上的层,管理流程(接下来显示哪个屏幕)。Router 负责机制,Coordinator 负责导航逻辑。Coordinator 使用 Router 执行转换。在 VIPER 中,Router 结合了这两种功能,而在 MVVM-C 中它们是分开的。

在移动应用程序中是否必须使用 Router?

不。对于有 3-5 个屏幕的应用程序,直接调用 navigationController.pushViewController 是正常解决方案。Router 在 10+ 个屏幕、deep link、推送通知和模块化架构时变得有用。Router 简化了导航测试,并允许集中处理来自任何来源(按钮、deep link、推送)的转换。

Router 如何与 Deep Links 关联?

URL Router 是 Router 的扩展,用于解析 deep link 和 universal link。URL Router 确定 URL 与应用程序屏幕之间的对应关系。例如,route myapp://profile/42 → ProfileViewController(userId: 42)。URL Router 集中处理来自不同来源的 deep link:推送通知、二维码、电子邮件链接、通用链接。

可以在没有 Coordinator 的情况下使用 Router 吗?

可以。Router 可以独立运行 — 作为全局 Navigator 或作为 VIPER 模块的组件。没有 Coordinator 的 Router — 只是将 UINavigationController 封装在协议之后。没有 Router 的 Coordinator — 更困难(ViewController 自己调用 push/present),但可行。最佳实践 — Router + Coordinator 一起使用。

Android 中的 Router 和 iOS Router 一样吗?

功能上 — 是的,两者都集中管理导航。实现不同:iOS Router — 协议 + UINavigationController 周围的类;Android — Jetpack Navigation Component 带有 XML 图和 NavController。Android Router 内置于框架(Navigation Component)中,iOS Router 是外部实现。Android Router 支持 Safe Args,iOS Router 不支持(需要泛型或 Codable)。

总结

  • Router — 封装屏幕间转换逻辑的路由模式
  • iOS Router — 带有 push/present/pop 方法的协议,围绕 UINavigationController
  • Android Router — Jetpack Navigation Component 带有 XML nav_graph 和 NavController
  • URL Routing — 通过 deep link 和通用链接的路由
  • Router vs Coordinator — Router 负责机制,Coordinator 负责导航流程
  • 应用 — 模块化架构、deep link、导航测试

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读