组件化项目的意义
组件化,简单来说,就是将一个APP的业务功能进行拆分,每一个功能都是一个单独的工程,每个工程都能独立运行,且只包含自己的业务,最后整个APP由多个拆分出的组件集成而成
组件化开发的优点有以下几点:
- 极大提高工程编译速度
进行组件化拆分后,每个业务或者功能都是一个单独的工程,这个单独的工程可以独立编译运行,编译运行速度快,减少时间成本; - 业务模块解耦,利于多人团队协作开发,提高团队开发效率
业务组件之间不能相互引用,每个组件都把对应的业务功能放在一个工程里去实现,彼此互不打扰。 在团队开发中,每个人只负责自己的业务模块,便于开发测试; - 提高功能重用性
不同的组件实现的业务功能不同,可以像搭积木一样任意排列形成新的APP
组件化架构设计图
phone module 和 Android Library 的区别
phone module: 新建出可以独立运行的模块,与创建项目时自动创建的app module 是一样的,在build.gradle中 是 apply plugin: ‘com.android.application’ ,android 配置下包含applicationId;
Android Library: 新建出的Android库,不能直接运行,可被其他module引用,在build.gradle 中,是library “apply plugin: ‘com.android.library’”,Android配置下不包含applicationId.
Gradle搭建组件化项目环境
为了使多个模块之间配置一致,则可以通过引入统一配置文件进行配置,配置过程如下:
- 在工程中创建config.gradle文件
- 在文件中设置统一配置内容
// 必须在ext标签下进行配置
ext {
// 标记是测试版本还是正式发布版本,在模块中可以根据这个值进行不同的配置
isRelease = true
//相关编译环境的版本配置
androidId = [
compileSdkVersion: 28,
buildToolsVersion :"29.0.0",
minSdkVersion : 21,
targetSdkVersion : 28,
versionCode: 1,
versionName :"1.0"
]
//不同模块的applicationId
appId = [
app : "com.example.zhangzd.zujiandemo",
order: "com.example.zhangzd.order",
personal: "com.example.zhangzd.personal"
]
//support包的版本
supportLibrary = "28.0.0"
//第三方依赖配置
dependencies = [
// ${supportLibrary}表示引用一个变量
"appcompat" : "com.android.support:appcompat-v7:${supportLibrary}",
"recyclerview": "com.android.support:recyclerview-v7:${supportLibrary}",
"constraint" : "com.android.support.constraint:constraint-layout:1.1.3",
"okhttp3" : "com.squareup.okhttp3:okhttp:3.10.0",
"retrofit" : "com.squareup.retrofit2:retrofit:2.5.0",
"fastjson" : "com.alibaba:fastjson:1.2.58",
]
}
- 在工程的build.gradle 中,通过 apply from : “config.gradle” 引入配置文件;
- 在模块的build.gradle中应用配置文件,以APP模块为例,配置文件如下
apply plugin: 'com.android.application'
//定义变量androidId等,引入配置文件中的配置信息,
def androidId = rootProject.ext.androidId
def appId = rootProject.ext.androidId
def support = rootProject.ext.dependencies
android {
// 通过创建的变量配置具体的信息
compileSdkVersion androidId.compileSdkVersion
buildToolsVersion androidId.buildToolsVersion
defaultConfig {
applicationId appId.app
minSdkVersion androidId.minSdkVersion
targetSdkVersion androidId.targetSdkVersion
versionCode androidId.versionCode
versionName androidId.versionName
// 这个方法接收三个非空的参数,第一个:确定值的类型,第二个:指定key的名字,第三个:传值(必须是String)
// 为什么需要定义这个?因为src代码中有可能需要用到跨模块交互,如果是组件化模块显然不行
// 切记:不能在android根节点,只能在defaultConfig或buildTypes节点下
buildConfigField("boolean", "isRelease", String.valueOf(isRelease))
multiDexEnabled false
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// 循环添加第三方依赖,最简单的方式,可以不循环一个一个添加
support.each{ k, v ->
implementation v
}
if (isRelease) {
implementation project(":order")
implementation project(":personal")
}
}
集成化模式开发、组件化模式开发
集成化模式开发:即模块是APP的组成部分,所有的模块组装起来便是一个完整的APP,在项目中的表现形式是,在一个工程中,只有一个phone module ,其他的只能作为Android 的library被引用,只能运行phone module ,其他模块不能直接运行。例如在一个APP中,首先由主模块(phone module)app模块,其次是Oder和Personal两个library,具体如下图
组件化模式开发:即每个模块都是一个phone module ,可以单独运行,单独调试。例如,除了app模块外,Order和Personal 都是phone module,可以单独运行,如图
在团队开发过程中,每个成员可能只开发一个功能模块,不同的人开发不同功能模块,此时需要组件化开发模式,每个模块都是一个单独的phone module,可以进行单独运行和测试,加快开发速度。当打包上线时,需要将所有的功能模块与主模块一同打包成一个APP,此时需要组件化开发模式,因此需要两种模式的灵活转换,我们也可以通过gradle 的配置实现灵活转换。要进行切换,就需要知道phone module 和Android library的区别,即上边介绍的两个区别。因此两种模式的切换,即非主模块phone module 和Android library的切换。步骤如下:
- config.gradle 配置文件中添加 isRelease = false ,该变量标识是否是测试环境还是正式打包环境;
- 在非主模块中进行如下配置,以order为例:
//通过定义的isRelease 变量,判断此时是否是测试环境吗,测试环境需要切换为组件化开发模式,即每个模块都是可以单独运行的
if (isRelease) {
// 是release时 ,将module设置为library
apply plugin: 'com.android.library'
}else {
// 不是是release时 ,将module设置为application
apply plugin: 'com.android.application'
}
def androidId = rootProject.ext.androidId
def appId = rootProject.ext.androidId
def support = rootProject.ext.dependencies
android {
compileSdkVersion androidId.compileSdkVersion
buildToolsVersion androidId.buildToolsVersion
defaultConfig {
//发布版本时没有applicationID
if (!isRelease) {
applicationId appId.order
}
minSdkVersion androidId.minSdkVersion
targetSdkVersion androidId.targetSdkVersion
versionCode androidId.versionCode
versionName androidId.versionName
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
support.each{k,v ->
implementation v
}
}
- 在主模块中,配置当非release模式下,不引用order等模块,当release模式时,引用
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
support.each{k,v ->
implementation v
}
// release 时才进行依赖
if (isRelease) {
implementation project(":order")
implementation project(":personal")
}
}
经过以上的配置,我们只需要在config.gradle 中更改isRelease变量,即可进行两种模式的自由切换。
组件化开发时的临时代码,集成化打包时动态隔离
当我们切换到集成开发模式并打包成一个Apk时,会发现一个问题,那就是在非主模块,我们的一些测试文件,比方说mainActivity等,只是在测试时才会用到,打包时不需要打包到apk,这个需要怎么解决呢?
我们可以通过配置sourceSet设置资源路径来解决这个问题
- 在非主模块的main路径下,新建debug路径,该路径下创建测试环境时的AndroidManifest.xml文件;
- 在Java.xxx.xxx.xxx.下创建debug,该路径下存放测试的Java代码
- 在该模块的build.gradle中配置sourceSet
if (isRelease) {
apply plugin: 'com.android.library'
} else {
apply plugin: 'com.android.application'
}
def androidId = rootProject.ext.androidId
def appId = rootProject.ext.androidId
def support = rootProject.ext.dependencies
android {
compileSdkVersion androidId.compileSdkVersion
buildToolsVersion androidId.buildToolsVersion
defaultConfig {
//发布版本时没有applicationID
if (!isRelease) {
applicationId appId.order
}
minSdkVersion androidId.minSdkVersion
targetSdkVersion androidId.targetSdkVersion
versionCode androidId.versionCode
versionName androidId.versionName
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
// 配置资源路径,方便测试环境中的内容不会被打包到apk中去
sourceSets {
main{
if (isRelease) {
//集成化模式,整个项目打包成一个apk
manifest.srcFile 'src/main/AndroidManifest.xml'
java {
// debug 目录下的文件不需要打包到apk中去
exclude '**/debug/**'
}
}else {
//组件化模式,需要单独运行
manifest.srcFile 'src/main/debug/AndroidManifest.xml'
}
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
support.each { k, v ->
implementation v
}
}
- 重新编译打包,就可以了
最后查看apk ,打出的apk中不包含测试用的A,B等类