Gradle是一个基□□于Apache Ant和Apache Maven概念的网□□□站项目自◉动化构建□□□□开源开发□□□工具。它使用一□□□□种基于Groovy的特定领✦域语言(DSL)来声明项◉目设置,抛弃了基□□□□于XML的各种繁□□琐配置。Gradle这门技术□□自动化构丨建被开发□□□出来的时□□□间已经不○短了,更多的有▼名气的开□□□源工程已□□经从原始□□□的ant,maven等原始的□□构建迁移□□□到了gradle中,例如:复杂的动□□□□态网站Spring制作,技术要求□□更高的安□□□□全网站建□□□□设都可以□□□□使用Gradle化繁为简,较为简单□□的一些有android端浏览器□□□□开发,java应用工程□□□等等,有许多人□□□□问我在从□□□事实际网□□站开发的□□□□工作中,如何能够◈使用到gradle呢,接下来我□□就来为大□□家去讲解□□□一下,如何在实□□际开发工□□作中去使□□□□用gradle让你更快□□□更简洁的□□□完成你的△工作。
我们都知□□□□道,任何一门□□技术都有□□□特定的使□□□□用场景,很少有计□□□算机语言□□□□能够应用□□在所有的□□□场景下,也就是说丨你碰到的□□□这个问题□□□□确实可以□□□□用gradle去解决,那我们才□□去考虑使●用gradle而不是为□□□了用而用,下面我来□□□讲一下,在我最近□□□的工作中□□用到gradle的一个实□□□例。
具体的技□□术背景需◢求我就不△展示说了,与gradle相关的技·术点就是,要在编译□□□□的时候,自动去生□□成一个类,然后将一□□些编译时♦期应用程□□□序的信息□□写到这个□□类中去,具体到我◈这里的需□□□求就是,要在编译▼的时候将□□□所有工程□□□中依赖了□□某个特定plugin(可以假定◤为所有apply了com.android.application)的module的名字都•统计到一□□个类中去。以供应用□□□□程序去使□□□用(实际需求◤是为所有app module生成路由□□□表).
总结一下▽我们的需◎求就是:要统计一□□□□个完整的♦工程中有□□哪几个工□□□程引入了com.android.application这个插件,那我们应□□□□该怎么做□□呢,当然你可□□以说,我手动创□□□建一个类,里面一个map每次新增❖了app module的时候,我手动加◈一行数据,这种方式□□□□固然可以,但是太烦□□□了,而且容易□□□□忘记,此时我们gradle自动化的◤技术就可□□以派上用□□场了。
下面,我把核心代码贴出来,大家就可以看明白。
第一步,我定义了♦一个单独❖的plugin,也就是说□□只要引入□□□□我这个自※定义Plugin你就可以□□□□实现这个◇功能。先来看一※下自定义plugin的主体很□□□简单。

没有任何☆难度,只需要继□□□成自Plugin这个接口,然后重写apply方法即可。这里我就△不再多说□□□□了,大家不了○解自定义Plugin的可以看□□□□我的课程◆或者其它□□□□一些文章。
第二步,开始判断□□□当前Project是否包含☆了com.android.application这个插件。如何判断,也非常简□□□单,只需要你□□□□对gradle的API有一定了◉解就可以□□□□知道,下面看我□□们的代码。
project.afterEvaluate {
if (it.plugins.hasPlugin(AppPlugin)) {
appModuleCompileDependencies << project.name
appModuleCompileDependencies.addAll(
project.getConfigurations().getByName("compile").dependencies.name)
}
// Record router modules' name, include library and app modules.
def routerModule = it.plugins.hasPlugin(
RouterPlugin) && appModuleCompileDependencies.contains(it.project.name)
if (routerModule) modulesSet.add(validateName(it.name))
}
通过it(即当前Project)plugins方法拿到□□每个Project的PluginContainer实例,然后使用□□□这个PluginContainer去判断,如果为true,则说明是▲一个app module,我们在最◢后一行代◈码,将其存储□□到一个set中去保存□□□起来。
第三步,上一步完◈成以后,那我们的moduleSet中就统计□□□到了工程□□□□中所有app module,那最后我□□□□们要做的□□□就是将这·些信息写□□□入到一个○类中去,让我们的□□源码去使◇用。一开始实□□□现这一步□□□□的时候,我是通过gradle去动态实○现一个Java类,然后将此□□□类去参与□□□□编译,核心就是□□□□将生成的java源文件添□□□□到加编译□□□环节中,核心API是:
/**
* Adds to the variant a task that generates Java source code.
*
* This will make the generate[Variant]Sources task depend on this task and add the
* new source folders as compilation inputs.
*
* The new source folders are also added to the model.
*
* @param task the task
* @param sourceFolders the source folders where the generated source code is.
*/
void registerJavaGeneratingTask(@NonNull Task task, @NonNull Collection sourceFolders);
这个方法□□□□是BaseVariant也就是每◣个最终要□□生成的变□□□□体都可以□□□□在编译时□□□期去为其□□□□动态的添□□□□加要编译□□的类。第一个参□□□数是生成java源文件对丨应的Task,第二个参□□□□数是生成□□□的Java源文件所□□□□在的目录。
这样,就实现了□□□□在我们编※译的时候,通过gradle动态的去□□□□保存一个□□□□工程中所◎有的app类型的module,那到这里▲是不是就□□□□结束了呢,功能上其□□实已经实□□□现了,但后来我□□又思考了□□□一下,我们在编□□□□译一个工□□□□程的时候,android-gradle-plugin这个插件□□总是会为□□□□我们生成❖一个BuildConfig类,这个类中□□其实也放□□□的是一些□□□编译期的□□一些信息,例如:是否是Debug,applictaionId等等,那我就在□□想,我直接将□□□□我们上面□□保存的信丨息,直接写入●到这个plugin会自动帮□□□我们生成◤的类不就□□□□可以了吗?于是我在□□□最后又优□□□□化了一下□□□我们的代□□□□码。
大家来看:
variants.all { BaseVariant variant ->
if (variant instanceof ApplicationVariant) {
//为generateBuildConfig这个Task添加额外Action
def generateBuildConfig = variant.generateBuildConfig
generateBuildConfig.doFirst {
def modules = new StringBuilder()
modulesSet.each {
modules.append(it).append(',')
}
items.add(new ClassFieldImpl("String", "ALL_MODULES", "\"${modules}\""))
}
}
为什么可□□以这样写□□□呢,其实思路□□很简单,既然BuildConfig这个Java源文件在□□□生成的时□□□□候会写入□□□□原始的一◆些信息,那我们是□□□不是找到□□□生成BuildConfigo类的Task,然后为其□□□□添加一项□□我们自己□□的数据不◆就可以了▼吗,看起来确□□□□实是可行★的,所以我们□□现在回过□□□□头来分析□□□一下上面□□我最终实□□□□现的代码,我们通过variant.generateBuildConfig就找到了□□□□生成BuildConfig这个Java源文件的Task,然后我们□□□知道Task都是可以□□为其添加Action的,所以我们□□最终通过generateBuildConfg.doFirst{}这个方法□□□为其添加□□□一个数据□□□□项即可。这样我们□□就完成了□□□最终要实□□现的gradle部分的相□□□□关功能。
整个工程□□的代码还□□□是比较复◤杂的,这里我只□□□□是复制出▼了gradle相关的一□□小部分代□□□码,后面其实·还有一个□□□□工程是专◢门为所有□□□的app module去生成路□□□由表,由于后面□□□的功能主□□□□要是APT注解处理□□□器的相关※功能,与我们的gradle关系不大,所以就不●再贴代码□□了。
好,到这里呢,我的这个□□□需求部分□□□□就通过gradle完成动态□□的解决了,完全无需□□我们手动□□□□去修改,其实gradle的功能是□□非常强大□□的,我们写Java代码也好,JS代码也好□□□□等等,我们控制□□□的都是源□□□码期,如果我们□□掌握了gradle就可以动□□□□态的控制◆编译时期。对我们能◈力的提高□□□□是非常的□□有帮助的。最后附一□□张图,是android-gradle-plugin中各Task的一个执◣行顺序。(注意:大家只看□□□□绿色的Task即可,其它颜色丨是其它Porject中的Task),