主流方案优缺点
路由 URL 统跳方案
使用路由URL统跳方案的优势是动态性及多端统一 (H5, iOS,Android,Weex/RN); 缺点是能处理的交互场景偏简单。所以一般更适用于简单 UI 页面跳转。一些复杂操作和数据传输,虽然也可以通过此方式实现,但都不是很效率。
服务注册方案
即每个模块提供自己对外服务的协议声明,然后将此声明注册到中间层。调用方能从中间层看到存在哪些服务接口,然后直接调用即可。
这种方式的优势也包括调用简单方便。代码自动补全和编译时检查都有效。实现起来也简单,协议的所有实现仍然在模块内部,所以不需要写反射代码了。同时对外暴露的只有协议,符合团队协作的“面向协议编程”的思想。劣势是如果服务提供方和使用方依赖的是公共模块中的同一份协议(protocol), 当协议内容改变时,会存在所有服务依赖模块编译失败的风险。同时需要一个注册过程,将 Protocol 协议与具体实现绑定起来。
业界里,蘑菇街的 ServiceManager 和阿里的 BeeHive 都是采用的这个方案。
基于反射的远程调用封装
但这种方式存在大量的 hardcode 字符串。无法触发代码自动补全,容易出现拼写错误,而且这类错误只能在运行时触发相关方法后才能发现。无论是开发效率还是开发质量都有较大的影响
这种方案的优势是调用简单方便,代码自动补全和编译时检查都仍然有效。 劣势是 category 存在重名覆盖的风险,需要通过开发规范以及一些检查机制来规避。同时 Mediator 只是收敛了 hardcode, 并未消除 hardcode, 仍然对开发效率有一定影响。
业界的 CTMediator 开源库,以及美团都是采用类似方案。
模块输出
每个业务模块的产出包括可执行文件和资源文件两部分。有2种选择:
- 生成 framework
- 生成静态库 + 资源 bundle.
使用framework的优点是输出在同一个对象内,方便管理。还能避免主程序文件过大, 导致启动速度变慢, 可以通过动态库懒加载来优化启动速度.
缺点是作为动态库载入,影响加载速度(启动阶段动态加载也会耗时, 但可以延后)。
另外如果使用framework,需要注意资源读取的问题。因为传统的资源读取方式无法定位到framework内资源,需要通过 bundleForClass:
才行。
总结
路由 | 优点 | 缺点 | 业界代表 |
---|---|---|---|
url-scheme | 1.通用,iOS/Android/Web2.服务器可动态配置页面跳转组件通信 | 1. 参数需集中文档维护;2.无法传递oc对象模型3.大量硬编码,需要注册scheme规则 | JLRoutes 蘑菇街MGJRouter |
protocol-class | 1.基于协议,有严格的参数检查2.无硬编码 | 1. 需要协议管理中心,所有协议暴露2. 需要注册协议 | 阿里BeeHive |
target-action | 1.基于runtime,无需注册2.扩展性好 | 1. 参数以dictionary形式传递,存在一定的硬编码,且无法校验参数 | CTMediator |
路由方案-实现
protocol-class-service
- 基于协议,编译期严格检查接口调用参数正确
- 代码健壮性、可维护性
- 使用service实现
路由方案-如何解决协议的注册?
关键是把protocol和实现的class关联起来
- Load方法注册
- attribute(section(“data”))
- 编译期把protocol和对应的实现class字符串保存在data数据段中
- 运行期app读取数据段,执行注册协议
- 配置表注册
- 从配置表中读取需要注册的protocol-class映射关系,执行注册
- 配置表可以打入安装包,或者动态下发
路由方案-问题
遇到的问题
- protocol文件增多,协议管理中心的膨胀
- 控制模块划分粒度
- 数据模型多个模块随意使用
- 抽取基础数据模型model下沉
- 新增category存放与业务相关数据