-
Notifications
You must be signed in to change notification settings - Fork 0
基础入门
基于 ARouter 的 Android 组件化快速开发框架
Android 初期 Eclipse 开发单一工程模式,所有代码都放在一个工程内,不同业务和模块存在不同的包下,在业务还没有那么多的时候,怎么做基本没什么问题,其实 Eclipse 也可以使用 Library ,即模块化的方式来构建。
2013年5月 Google 推出了官方开发工具 Android Studio 并基于 Gradle 构建更灵活的 Android 应用程序,引入 Project、Module 概念,Project 相当于 Eclipse 的工作区间,Module 相当于 Project 可以做为一个 Library 被其他工程引用也可以做为一个独立的 Application,基于以上特性更好的支持了模块化、组件化。模块化最初目的是将同一类型的代码整合在一起,比如数据库模块,视频模块等,做到了代码隔离、高内聚、松耦合并对外提供统一的开放接口用于通信。这种模式的优点相对于单工程很明显模块更灵活,耦合低。一句话的解释就是根据不同的业务,将一个项目可以共享的部分抽离出来,形成独立的 Library,哪里用到就插到哪里,就是模块化。
组件化的核心思想在于代码的重用,比如一个登录组件,可能在多个项目里基本是差不多的,那么基本可以做很少的改动即可达到重用的目的,在移动端的组件化方案中组件就是一个可以独立运行的完整工程,一个组件化工程基本至少需要包括一个底层的 Common 模块和若干个业务组件,每个业务组件依赖 Common 模块,也可以根据需要对 Common 再进行拆分,比如可以再拆分出一个专门存放共通资源文件的 CommonRes 库,这些都是很灵活的,根据实际需要调整即可。那么底层模块主要功能就很明显了它负责业务组件的基础架构、组件通信等功能,从架构的横向划分模块、纵向划分层次的思想来说,底层的 Common 模块相当于模块化思想就是横向分块,组件化是纵向分层,里面可能包含多个模块或依赖一些模块,每个组件也需要有自己的架构,这时需要引入职责划分的分层思想,也就是常见 MVC、MVP、MVVM,这三种比较典型,一般是以页面(Activity、Fragment)为单位,划分为多个层级,每个层级只做自己的应该做的逻辑。那么在开发阶段组件也可以存在两种模式,即在单独的调试阶段 Debug 模式单独调试业务组件,多人协同开发,在发布时的 Release 模式选择性地集成到主工程中,做到拆解灵活。
- 业务增长导致代码量不断增加,各种业务逻辑如同蜘蛛网一样交织混合在一起,在多人协作开发、调试、测试过程中带来效率上的影响
- 开发一个功能点甚至需要了解整个工程的业务,避免代码的改动而影响其它业务,无形中增加了维护成本
- 调试代码需要编译整个工程,虽然 AS 支持 Instant Run 可以快速部署代码,但由于代码量不断增大,资源文件多的情况下,先不说编译速度,光安装一次可能就要用好几分钟的时间,曾经公司有个项目光资源文件最后达到一个G,安装一次就要 20 多分钟
- 公司内部没有统一的快速开发框架,每个项目采用的技术实现方式都不一样,每个开发人员的编码风格也不一致,导致开发人员在项目之间的沟通困难,他的代码你看不懂,你的代码他看不明白
- 模块的复用问题,某些项目可以共用的功能模块,混杂在整个工程里面,导致无法复用或复用困难,更别说扩展
- Mainfest 集中式管理比较臃肿的问题
以本项目为例的目录结构图如下,主要组成包括 App主工程(也有叫壳工程的)、基础组件、功能组件、业务组件

管理各个业务组件,控制哪些业务组件可以集成到主工程里,基本没有具体的业务功能,还有负责打包工作
支撑业务组件的基础,提供多数业务组件需要的基础功能,例如提供网络通信,数据库,日志等
支撑某些业务组件的基础功能,例如某些第三方SDK,第三方库等
根据具体业务独立形成的一个的工程,这里编写具体的业务逻辑,可以脱离主工程单独运行、调试
一些关于组件化项目配置的讲解
这里有一个很重要的文件,在基于 Gradle 构建的项目根目录中有一个名为 gradle.properties 配置文件,它的使用场景是在里面定义一些敏感信息如账号、密码、签名信息或是全局的配置信息等,并且这些配置信息可以在其他 Module 的 build.gradle 获取到,达到全局控制的作用,那么组件的调试开关就可以写在这个文件里,全局控制组件模式的切换。
在 gradle.properties 文件内添加 isBuildModule=false 参数
# 为 true 时,各个业务模块能够单独运行,修改此变量值,点击重新 "Sync Now" 通过运行按钮左边的下拉选择不同的 Module 运行
# 为 false 时,每个业务 Module 无法单独运行只能作为 Module 引入,将整个组件集成到 App 模块,此时只有 App 模块可以运行
isBuildModule=false
根据需要可以添加多个开关对各个组件分开控制,如 Module_Login 对应 isLoginModule,Module_User 对应 isUserModule
Android Studio 的 Module 有两种模式,该模式在 Module 的 build.gradle 文件中配置,当组件处于 application 模式时为可以独立运行的 Android 程序,当组件处于 library 模式时为不能独立运行,必须依赖在其他 Android 程序才可以运行,结合上面定义好的 isBuildModule 就可以在 Module 的 build.gradle 里控制,参考代码如下
if (isBuildModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
每个组件会涉及两个 AndroidManifest.xml 管理,分别放在各自组件 main 目录的 debug、release 目录里,在组件单独调试时调用 debug 目录的 Manifest 单独用于声明这个组件需要的四大组件、权限管理及一个完整 Android APP 所具有的的所有属性,当组件处于集成模式时调用 release 目录的 Manifest,此时每个业务组件的 AndroidManifest.xml 都要合并到主工程中,此时需要去掉一些声明属性,主要有 Application 的声明、权限声明、组件入口声明,否则合并的时候会发生冲突。控制 Manifest 文件切换代码如下。
sourceSets {
main {
if (isBuildModule.toBoolean()) {
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
}
}
}
这段代码每个组件都是一样的,可以提取到一个公共的配置文件中,参考 common_module.gradle
首先工程在拆分成组件化后可能会存在以下一些问题,这些问题也是为什么我们需要使用路由的原因
- 组件页面的跳转问题,原始方式是使用显式 Intent,但是这种强引用方法在组件化的多 Module 里每个页面(Activity、Fragment)存放在自己的组件中,根本就无法跳转也无法隔离组件
- 还有一种隐式跳转 Intent,这种方式使用过多会造成协作困难,因为调用时候不知道调什么参数,用错了甚至可能会崩溃,而且注册了 Scheme 的 Activity 页面都可以直接被其他应用打开,存在安全风险,这种模式使用场景一般是第三方授权功能用的比较多
- 某些功能需要动态拦截跳转,例如在进入需要登录的页面时判断是否登录,登录成功后再自动转入目标页面
- 无法动态修改路由,如果页面出错,无法动态降级
- Html5、Android、iOS 的统一跳转地址问题
- Fragment 拆分与跳转问题