Android组件化初探
1. 现状
随着业务增加,代码量急剧增加,大大延长了编译时间,短则3min,长则7、8min;很多同学为节省开发时间,自己新建新的app,完成开发后,再合并到project中;组件化的目的就是为了解耦,将业务模块独立出来,自成一个apk,这样开发期间能提高效率
2. 原理
编译期间动态设置自己业务Module属性(app/library)
在开发期间,只需要编译自己的业务模块代码,并将自己业务模块Module设置app;这样能很大程度上提高编译速度,提高开发效率;在发版期间将自己业务Module设置为libray模式即可
3. 需要解决的问题
- 需要在编译期间动态设置自己业务模块属性(app/library)
- 开发模式应该存在一个DebugActivity 以作为app启动页;发布模式应该将其忽略不参与打包
- 为保证资源不与其他模块存在冲突,应限定自己module所有资源带有指定前缀
- 业务模块可能会存在依赖其他业务模块功能,如何实现?
- debug模式和发布模式下清单文件应该单独区分
- 业务module在运行期间可能会对debug/发布模式做不同操作处理,java代码层如何区分?
- 当自己业务模块代码增加时,如何提高开发效率?
4. 实现
4.1 编辑根目录gradle.properties文件
为了能够区分开发模式和发布模式,我们可以在项目根目录gradle.properties文件中添加一个属于自己业务模块变量,以区分是开发模式还是发布模式(下面以module1为样例进行说明)
#标识MODULE1以app方式启动,发布时可改为false
MODULE1_IS_APP = true
4.2 编辑settings.gradle文件
让gradle动态指定需要参与编译的module
if(MODULE1_IS_APP.toBoolean()){
include ':module1', ':framework', ':baseresource'
}else{
include ':app', ':module1', ':framework', ':baseresource'
}
4.3 编辑moudle1工程中build.gradle文件
为能在编译期间动态设置通通花module是以app还是library需要添加如下代码:
//解决问题1
if (MODULE1_IS_APP.toBoolean()) {
apply plugin: 'com.android.application'
//解决问题7,关于如何集成freeline
//参见(http://blog.youkuaiyun.com/dbs1215/article/details/64166592)此处不再阐述请参考
//apply plugin: 'com.antfortune.freeline'
} else {
apply plugin: 'com.android.library'
}
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
if (MODULE1_IS_APP.toBoolean()) {
multiDexEnabled true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
buildTypes.each {
//解决问题6 代码中可以通过BuildConfig.MODULE1_IS_APP获取
it.buildConfigField "boolean", "MODULE1_IS_APP", MODULE1_IS_APP
}
//解决问题3 (只能做到布局文件,字符串等资源前缀,java类,图片需要自己处理)
resourcePrefix "module1_"
sourceSets {
main {
//解决2、5问题
if (MODULE1_IS_APP.toBoolean()) {
//如果是app启动,使用该清单文件
manifest.srcFile 'src/main/xml/app/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/xml/library/AndroidManifest.xml'
java{
//debug包不参与打包
exclude '**/debug/**'
}
}
}
}
configurations {
all*.exclude group: 'com.android.support', module: 'support-v4'
all*.exclude group: 'com.android.support', module: 'support-annotations'
}
}
dependencies {
//业务module需要依赖的相关库
compile fileTree(dir: 'libs', include: ['*.jar'])
compile project(':framework')
compile project(':baseresource')
}
4.4 问题4如何解决?
可以通过依赖注入来实现
首先可以声明一个接口IDependService
添加Module1需要依赖其他Module的方法在依赖方Module某个路径下实现该接口
- 在Module1添加一个类Module1SDK(单例)对象初始化时通过反射实现依赖注入
具体如何实现可以参见末尾代码链接
依然存在的问题
- 当自己的业务module1联调依赖于其他业务module功能时,需要以app为主工程启动,耗费时间,暂时没找到别的有效办法
- 当自己的业务module1依赖于公共组件/基础模块,但未下沉,无法引用,尴尬。。。。只能通过copy(简单点)/下沉(改动较大)方式来做
思考
- 如何定义并剥离Module
- 组件与组件间通讯(Router)