一、前言
从明面上看,Gradle 是一款强大的构建工具,但 Gradle 不仅仅是一款强大的构建工具,它更像是一个编程框架。Gradle 的组成可以细分为如下三个方面:
groovy 核心语法:包括 groovy 基本语法、闭包、数据结构、面向对象等等。
Android DSL(build scrpit block):Android 插件在 Gradle 所特有的东西,我们可以在不同的 build scrpit block 中去做不同的事情。
Gradle API:包含 Project、Task、Setting 等等。
可以看到,Gradle 的语法是以 groovy 为基础的,而且它还有自己独有的 API,所以我们可以把 Gradle 认作是一款编程框架,利用 Gradle 我们可以在编程中去实现项目构建过程中的所有需求。想要随心所欲地使用 Gradle,我们必须提前掌握好 groovy。需要注意的是,Groovy 是一门语言,而 DSL 一种特定领域的配置文件,Gradle 是基于 Groovy 的一种框架工具,而 gradlew 则是 gradle 的一个兼容包装工具。
Gradle 有以下优势:
- 灵活性:相对于 Maven、Ant 等构建工具,Gradle 提供了一系列的 API 让我们有能力去修改或定制项目的构建过程。例如我们可以利用 Gradle 去动态修改生成的 APK 包名。
- 粒度性:使用 Maven、Ant 等构建工具时,我们的源代码和构建脚本是独立的,而且我们也不知道其内部的处理是怎样的。但是 Gradle 则不同,它从源代码的编译、资源的编译、到生成 APK 的过程中都是一个接一个来执行的。此外,Gradle 构建的粒度细化到了每一个 task 之中。并且它所有的 Task 源码都是开源的,在我们掌握了这一整套打包流程后,我们就可以通过修改它的 Task 去动态改变其执行流程。例如 Tinker 框架的实现过程中,它通过动态地修改 Gradle 的打包过程生成 APK 的同时,也生成了各种补丁文件。
- 扩展性:Gradle 支持插件机制,所以我们可以复用这些插件,就如同复用库一样简单方便。
兼容性:Gradle 不仅自身功能强大,而且它还能兼容所有的 Maven、Ant 功能,也就是说,Gradle 吸取了所有构建工具的长处。
可以看到,Gradle 相比于其它构建工具,其好处不言而喻,而其最核心的原因就是因为 Gradle 是一套编程框架。
二、Gradle 的生命周期
所谓 Gradle 的生命周期,即 gradle 的执行流程,也就是 Gradle 先执行什么后执行什么。我们看下它的流程图:可以看到,gradle 的执行流程分了 初始化、配置、执行 三个阶段,上图中的 project、task 我们接下来几篇会详细介绍。下面我们看看这几个阶段。
2.1 初始化阶段
初始化阶段会读取根工程中的 setting.gradle 中的 include 信息,确定有多少工程加入构建,然后会为每一个项目(build.gradle 脚本文件)创建一个个与之对应的 Project 实例,最终形成一个项目的层次结构。
与初始化阶段相关的脚本文件是 settings.gradle,而一个 settings.gradle 脚本对应一个 Settings 对象,我们最常用来声明项目的层次结构的 include 就是 Settings 对象下的一个方法,在 Gradle 初始化的时候会构造一个 Settings 实例对象,以执行各个 Project 的初始化配置。
此外,在 settings.gradle 文件中,我们可以指定其它 project 的位置,这样就可以将其它外部工程中的 moudle 导入到当前的工程之中了。示例代码如下所示:
if (useStepMoudle) {
// 导入其它 App 的 step 步数模块
include "step"
project(":step").projectDir = new File("../OtherApp/step")
}
2.2 配置阶段
配置阶段的任务是执行各项目下的 build.gradle 脚本,完成 Project 的配置,与此同时,会构造 Task 任务依赖关系图以便在执行阶段按照依赖关系执行 Task而在配置阶段执行的代码通常来说都会包括以下三个部分的内容,如下所示:
- 1)、build.gralde 中的各种语句。
- 2)、闭包。
- 1)、Task 中的配置段语句
需要注意的是,执行任何 Gradle 命令,在初始化阶段和配置阶段的代码都会被执行。
2.3 执行阶段
在配置阶段结束后,Gradle 会根据各个任务 Task 的依赖关系来创建一个有向无环图,我们可以通过 Gradle 对象的 getTaskGraph 方法来得到该有向无环图。并且当有向无环图构建完成之后,所有 Task 执行之前,我们可以通过 whenReady(groovy.lang.Closure) 或者 addTaskExecutionGraphListener(TaskExecutionGraphListener) 来接收相应的通知,其代码如下所示:
gradle.getTaskGraph().addTaskExecutionGraphListener(new TaskExecutionGraphListener() {
@Override
void graphPopulated(TaskExecutionGraph taskExecutionGraph) {
}
})
然后,Gradle 构建系统会通过调用 gradle <任务名> 来执行相应的各个任务。
可以看到,整个 Gradle 生命周期的流程包含如下 四个部分:
- 首先,解析 settings.gradle 来获取模块信息,这是初始化阶段。
- 然后,配置每个模块,配置的时候并不会执行 task。
- 接着,配置完了以后,有一个重要的回调 project.afterEvaluate,它表示所有的模块都已经配置完了,可以准备执行 task 了。
- 最后,执行指定的 task 及其依赖的 task。
2.4 生命周期监听
上面我们学习了 Gradle 的执行生命流程,下面我们在它的监听回调中做一些输出。首先在项目根目录的 build.gradle 中添加如下监听代码:
//配置阶段开始前的监听回调,也就是初始化阶段和配置阶段之间
beforeEvaluate {
println "准备执行配置阶段..."
}
//配置阶段完成后的监听回调,执行阶段之前的监听
afterEvaluate {
println "配置阶段执行完毕..."
}
//gradle生命周期执行完毕后的回调监听
this.gradle.buildFinished {
println "执行阶段执行完毕..."
}
this.gradle.beforeProject{
}
this.gradle.afterProject{
}
在根目录的 setting.gradle 中添加如下代码:
include ':app'
println "初始化阶段开始"
接下来我们执行一个简单的 gradle 命令:gradle clean