组件化,简单来说,就是将一个APP的业务功能进行拆分,每一个功能都是一个单独的工程,每个工程都能独立运行,且只包含自己的业务,最后整个APP由多个拆分出的组件集成而成
组件化开发的优点有以下几点:
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.
为了使多个模块之间配置一致,则可以通过引入统一配置文件进行配置,配置过程如下:
// 必须在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",
]
}
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的切换。步骤如下:
//通过定义的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
}
}
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设置资源路径来解决这个问题
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
}
}