组件化路由
问题
iOS 组件化中主流的路由方案有哪些?各有什么优缺点?
答案
三种主流方案
1. URL Router(类似蘑菇街)
// 注册
Router.register("myapp://user/profile") { params -> UIViewController in
let userId = params["id"] as? String ?? ""
return UserProfileVC(userId: userId)
}
// 跳转
Router.open("myapp://user/profile?id=123")
- ✅ 支持 Deep Link、跨端统一
- ❌ 无编译检查,参数传递靠字符串
2. Protocol Router(类似 BeeHive)
// 定义协议(放在公共模块)
protocol UserServiceProtocol {
func showProfile(userId: String, from: UIViewController)
}
// 实现(在 User 模块内部)
class UserServiceImpl: UserServiceProtocol {
func showProfile(userId: String, from: UIViewController) {
let vc = UserProfileVC(userId: userId)
from.navigationController?.pushViewController(vc, animated: true)
}
}
// 注册
ServiceRouter.register(UserServiceProtocol.self, impl: UserServiceImpl())
// 调用方
let service = ServiceRouter.resolve(UserServiceProtocol.self)
service?.showProfile(userId: "123", from: self)
- ✅ 类型安全,编译期检查
- ❌ 每个模块需要暴露协议到公共层
3. Target-Action(CTMediator 思路)
// 中间人调用,利用 ObjC Runtime
class CTMediator {
func performTarget(_ name: String, action: String, params: [String: Any]) -> Any? {
let cls = NSClassFromString("Target_\(name)") as? NSObject.Type
let target = cls?.init()
let sel = NSSelectorFromString("Action_\(action):")
return target?.perform(sel, with: params)?.takeUnretainedValue()
}
}
- ✅ 无需注册,利用 Runtime
- ❌ 字符串硬编码,仅支持 ObjC
方案对比
| 方案 | 类型安全 | Deep Link | 学习成本 | 适合场景 |
|---|---|---|---|---|
| URL Router | ❌ | ✅ | 低 | H5 交互多、需要 Deep Link |
| Protocol Router | ✅ | ❌(需桥接) | 中 | 纯 Native、注重类型安全 |
| Target-Action | ❌ | ❌ | 低 | ObjC 项目 |
实际项目推荐
混合使用:Protocol Router 用于模块间 Swift 调用,URL Router 用于 Deep Link / Push 通知跳转。
常见面试问题
Q1: 如何处理模块间页面跳转?
答案:通过路由层解耦。模块 A 不直接 import 模块 B,而是通过注册的路由(URL 或 Protocol)间接获取目标 VC,消除编译依赖。
Q2: Deep Link 和路由的关系?
答案:Deep Link 是外部唤起 App 并导航到特定页面的机制(Universal Links / URL Scheme)。路由是 App 内部的页面跳转机制。通常让 Deep Link 解析后调用内部路由完成跳转,保持跳转逻辑统一。