一. 架构演进综述
graph LR
单模块+分包-->模块化
模块化-->组件化
组件化-->插件化
项目初期启动,业务形态单一,简单的单一模块+分包就能满足业务开发需求,
随着用户的增多,部分业务变得复杂,比如登录,网络通信,统计上报,社会分享等,简单分包会导致依赖不清晰,从而进化到模块化开发,将不同的业务组织成模块,模块与模块之前存在依赖关系,模块之间可以互相调用
随着业务的变更,在追求研发效能的今天,新的项目启动会要求能够快速迭代,因此希望能够复用已有的能力,模块的设计由于存在相互的依赖,导致不容易抽离出来作为aar被依赖,组件化的需求诞生,组件化梳理清楚组件之间的依赖,并且通过反射的形式进行组件通信,达到快速复用
随着业务的继续壮大,很多的业务包含多个组件,并且业务形态可能在多个产品线上被复用,如何能够让单一团队来维护业务,插件化的需求诞生,插件化能够将业务打包成独立的apk,被不同的产品依赖。
一. 组件化的目标
组件化是随着业务不断壮大之后的必然结果,组件化不能舍本逐末,它的本质在于:
- 1.项目解耦合,提升组件的原子性
- 2.组件的高可用,提升研发效率
二. 组件化的分层设计
- 1.分层设计思路
按照是否包含UI和是否包含业务来区分为四个象限,象限依赖关系为 1 -> 4 -> 2 -> 3
- 2.分层设计概览
根据分层设计思路,与依赖关系,得到分层设计结果
三. 组件化的操作流程
- 1.抽象公共的config.gradle
config.gradle被所有的组件依赖,它根据组件的设计和调试模式来确定组件的类型
if (isModule() || isApp()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
- 2.对于不同的组件,为了防止资源冲突,我们定义资源的命名方式,强制以模块的名作为资源的前缀
if (!isApp()) {
resourcePrefix "${project.name}_"
}
- 3.当组件处于调试模式时,需要单独的applicationId
if (isApp()) {
applicationId c.applicationID
} else if (isModule()) {
applicationId "${c.applicationID}.${this.name}"
} else {
println("found lib == com.huya.${this.name}")
}
- 4.对于组件,在调试模式下和组件模式下,需要对源码和manifest文件做区分
sourceSets {
main {
if (isApp() || isLib()) {
manifest.srcFile 'src/main/AndroidManifest.xml'
} else {
if (isModule()) {
manifest.srcFile 'src/main/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/release/AndroidManifest.xml'
java {
//release 时 runonly 目录下文件不需要合并到主工程
exclude '*runonly/**'
}
}
}
jniLibs.srcDirs = ['libs']
}
}
- 5.为了方便管理依赖版本,将所有的依赖版本抽象到version.gradle中
ext {
c = [
compileSdkVersion: 29,
buildToolsVersion: "29.0.3",
minSdkVersion : 21,
targetSdkVersion : 29,
versionCode : vCode,
versionName : version,
VSupportSdk : '28.0.0',
VRetrofitSdk : "2.4.0",
VOkhttp : "3.11.0",
VRxlifecycle : "3.1.0",
VRxJava : "2.1.0",
VGlide : "4.12.0",
vConstraint : "1.1.3",
VButterknife : "10.2.2",
VExoplayer : "2.9.2",
VOkDownload : "1.0.7",
applicationID : packageName
]
commons_io = 'commons-io:commons-io:2.4'
butterknife = "com.jakewharton:butterknife:${c["VButterknife"]}"
b
}
四. 组件化的通信与数据依赖
由于组件之间存在通信,通信的数据内容组织方式包含两种
- 1.通用格式 如pb , json , jce等
- 2.格式化结构 xxBean
由于业务请求的数据常常被封装成bean,因此在传输过程中需要频繁的拆装箱,为了解决这个问题,将数据模块抽象出来,让所有的组件都依赖与数据模块,这样所有的数据结构可以在不同的组件之间流通,这种方式对组件本身不友好,但是可以极大的减少数据传输的序列化与反序列化的消耗
五. 组件化的调试与发布
通过控制开关来设置组件模式,当设定为组件模式时,可以单独运行,否则可以被依赖
# is_Debug=true,设置其他组件true,则为组件调试模式
# is_Debug=false ,app模式
is_Debug=false
is_umeng=false
is_user=false
is_oss=false
is_video=false
is_laboratory=false
is_huyavideo=false
is_push=false
is_videoedit=false
is_dlna=false
六. 组件见通信
采用ARouter解耦各个模块的依赖
七. 组件生命周期
AppLifecycle 用于将壳工程Application的生命周期分发到各个业务组件