首先声明一点标题所说的组件化, 并非类似Small的插件化. 如果没有搞错的话, 可以继续往下看.
android中实现组件化的方案一般是在gradle.properties里设置一个变量, 区分合并运行还是拆分运行.
//'mine'模块中的build.gradle
if (IS_DEV_MODE.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}上面是最主要的设置, 细分下来gradle中需要修改的地方不少, 例如applicationId, AndroidManifest的区分, 主app的依赖问题等等. 但是在修改gradle.properties属性之后需要一次同步. 一次同步的耗时对于一些低端机子会比较耗时, 没错就是我之前用的陈年老笔记本.
所以, 我写了个简单的plugin, 避免每次跑app和跑module时设置属性在同步的问题.
这里并不介绍怎么编写自定义插件, 只是提出这么个东西希望跟大家一起讨论目录.
目录很简单, 并且每个文件都是几十行, 很简单的plugin.
首先说明一下每个project分三种类型, 公共组建, 模块. 公共组建为library, module和app为application, 依赖模块时将动态改为library.
public class RootPlugin implements Plugin<Project>{
private Project rootProject //记录跟目录Project, 用于获取扩展
@Override
void apply(Project rootProject) {
//创建一个task, 打包时用
rootProject.task('packing', group: 'pack', dependsOn: ':app:assembleRelease')
this.rootProject = rootProject
//创建扩展属性
//该扩展总共定义了三个变量,
// pack 打正式包
// debugApp debug模式下跑app
// moduleProjectList 各个模块的Project集合
rootProject.extensions.create('root', RootExtension.class)
//获取第一个命令参数
def param = rootProject.gradle.startParameter.taskNames[0];
println("param -> $param")
//根据参数判断是整合还是, 分开, 这里只是用简单判断了一下
if (param != null){
if (param == 'rootExt'){
//如果是 'packing', 则为 -> 正式包
rootExt.pack = true
}else {
//AS中 跑app那么他的参数是 :app:assembleDebug
if (param.startsWith(':app:assemble')){
if (param.contains('Debug')){
rootExt.deBugApp = true
}else if (param.contains('Release')){
rootExt.pack = true
}
}
}
}
println("start changeDynamic -------------------> ")
def moduleList = rootExt.moduleProjectList
rootProject.subprojects { subProject ->
def subProjectName = subProject.name
//组件化一般分为, app, 模块, 以及公共组件
//这里简单的用各个模块的名称做了区分
switch (getType(subProjectName)) {
case Type.APP: //app
subProject.apply plugin: AppPlugin
break
case Type.LIB: //公共组件
subProject.apply plugin: LibPlugin
break
case Type.MODULE: //
// 模块的project需要加入到 扩展属性中
moduleList.add(subProject)
subProject.apply plugin: ModulePlugin
break
}
}
}
public RootExtension getRootExt(){
return rootProject.rootExt
}
private static Type getType(String projectName){
if ('app' == projectName){ //'app'
return Type.APP
}else if (projectName != null && projectName.startsWith('base')){ //公共组件一般以 'base' 开头
return Type.LIB
}else {
return Type.MODULE
}
}
static enum Type{
APP,LIB,MODULE
}
}先看下简单的LibPlugin
class LibPlugin implements Plugin<Project> {
@Override
void apply(Project subProject) {
//这里只考虑只有一个公共组建
//获取root的拓展属性
def rootExt = subProject.rootProject.rootExt
subProject.afterEvaluate {
//添加 IS_DEV BuildConfig
//根据是否是正式包做区分
it.android.defaultConfig.buildConfigField('boolean', 'IS_DEV', rootExt.pack ? 'false' : 'true')
//区分sourceSets
if (rootExt.pack || rootExt.deBugApp) {
//sourceSets
subProject.android.sourceSets.main.manifest.srcFile 'src/release/AndroidManifest.xml'
}else{
//sourceSets
subProject.android.sourceSets.main.manifest.srcFile 'src/debug/AndroidManifest.xml'
subProject.android.sourceSets.main.java{
exclude 'src/debug/**'
}
}
}
}
}接着看一下AppPlugin
class AppPlugin implements Plugin<Project> {
@Override
void apply(Project subProject) {
def rootExt = subProject.rootProject.rootExt
subProject.afterEvaluate {
//动态设置 versionCode
subProject.android.defaultConfig.versionCode = Integer.parseInt(new SimpleDateFormat("yyMMdd", Locale.CHINA).format(new Date()))
def dependencies = subProject.configurations.compile.dependencies
//添加其他模块依赖
if (rootExt.pack || rootExt.deBugApp) {
// 移除 baseModule依赖
// app和模块的build.gradle中默认都依赖公共组件, 所以当整合的时候
// 移除掉公共组建, 貌似不移除也无伤大雅
dependencies.remove(dependencies.find{
it.name == 'base_module' //这里简单的用名称移除
})
// 这里就是将扩展属性中模块project的集合, 依次添加到'app'的依赖
// 我们默认所有模块都是apply plugin: 'com.android.application'
// 如果不改为library那么依赖的时候就会报错
// 如何动态改为library马上介绍
it.rootProject.rootExt.moduleProjectList.each {
subProject.dependencies.add('compile', it)
}
}
}
}
}class ModulePlugin implements Plugin<Project> {
private File mTempBuildFile
@Override
void apply(Project subProject) {
def rootExt = subProject.rootProject.rootExt
//...省略 设置sourceSets 和LibPlugin一样
// 修改build.gradle文件
// 这里就是最关键的代码, 动态的修改模块是application还是library
// 这部分的代码是 Small插件化的gradle代码照搬过来的,
// 有兴趣的可以去和研究一下 Smallgradle插件的源码
if (rootExt.pack || rootExt.deBugApp) {
mTempBuildFile = new File(subProject.buildFile.parentFile, "${subProject.name}~")
subProject.beforeEvaluate {
def text = it.buildFile.text.replaceAll("""com.android.application""", """com.android.library""")
it.buildFile.renameTo(mTempBuildFile)
it.buildFile.write(text)
}
subProject.gradle.buildFinished {
if (mTempBuildFile != null && mTempBuildFile.exists()) {
subProject.buildFile.delete()
mTempBuildFile.renameTo(subProject.buildFile)
}
}
}
}
}最后, 只要在根目录的build.gradle中使用自定义的插件就可以了.