Android Studio默认的工具是Gradle,通常开发者不需要了解Gradle的脚本配置,也能开发出一个App,但是如果你需要修改打包中的输出目录、提高打包速度的话,就要对Gradle有个深入的了解了。而在开发学习Gradle不能仅仅把它当做一个工具来学习,更应该把它当成编程框架来看,这里是Gradle API文档,我们再编写编译脚本,其实就是在玩 Gradle的API。
Gradle的组成可以分为三部分:
- groovy核心语法
- Build script block
- Gradle API:包含project、Task/Settiing等等,也是接下来重点介绍的。
Gradle优势
- 在灵活性上,Gradle支持基于groovy语言编写脚本,侧重于构建过程的灵活性,适合于构建复杂度较高的项目,可以完成非常复杂的构建。
- 在粒度性上,Gradle 构建的粒度细化到了每一个 task 之中。并且它所有的 Task 源码都是开源的,在我们掌握了这一整套打包流程后,我们就可以通过去修改它的 Task 去动态改变其执行流程。
- 在扩展性上,Gradle 支持插件机制,所以我们可以复用这些插件,就如同复用库一样简单方便。
Grale 构建生命周期
下面来看下gradle的执行命令,执行./gradlew build
可以说是最复杂的task命令了。 (./gradlew是mac中的语法)
可以看到每次都会执行很长时间,是因为build的task任务依赖了很多任务,它会把它所依赖的task执行完之后,才会执行自己的task.。我们还是先了解下Gradle的构建过程。
Gradle的构建过程可以分为三部分:初始化阶段、配置阶段和执行阶段。
初始化阶段
Gradle为每个项目创建一个Project实例,在多项目构建中,Gradle会找出哪些项目依赖需要参与到构建中。与初始化相关的的脚本是settings.gradle
,会读出整个工程中有多少个project.
配置阶段
配置阶段的任务是执行各项目下的build.gradle脚本,完成Project配置,并且构造Task任务依赖关系图以便在执行阶段按照依赖关系执行Task。
每个build.gradle
对应一个Project
对象,配置阶段执行的代码包括build.gralde
中的各种语句、闭包以及Task
中的配置段语句。
执行阶段
在配置阶段结束后,Gradle会根据任务Task的依赖关系会创建一个有向无环图,还可以通通过Gradle对象的getTaskGraph方法访问,对应的类是TaskExecutionGraph,然后通过调用gradle <任务>执行对应任务。
Gradle生命周期监听
Project中添加生命周期监听
现在我们来看下平时开发中最常用的监听方法:
//在 Project 进行配置前调用
void beforeEvaluate(Closure closure)
//在 Project 配置结束后调用
void afterEvaluate(Closure closure)
接下来用个例子来验证下结果:
setting.gradle
include ':app'
println '初始化阶段开始...'
根目录下的build.gradle
//对子模块进行配置
subprojects { sub ->
sub.beforeEvaluate { proj ->
println "子项目beforeEvaluate回调..."
}
}
println "根项目配置开始---"
task rootTest {
println "根项目里任务配置---"
doLast {
println "执行根项目任务..."
}
}
println "根项目配置结束---"
app目录下的build.gradle
println "APP子项目配置开始---"
afterEvaluate {
println "APP子项目afterEvaluate回调..."
}
task appTest {
println "APP子项目里任务配置---"
doLast {
println "执行子项目任务..."
}
}
println "APP子项目配置结束---"
执行下`./gradlew clean,得到如下的打印结果:
初始化阶段开始...
根项目配置开始---
根项目里任务配置---
根项目配置结束---
子项目beforeEvaluate回调...
APP子项目配置开始---
APP子项目里任务配置---
APP子项目配置结束---
APP子项目afterEvaluate回调...
Gradle中添加生命周期监听
在setting.gradle
中添加:
include ':app'
gradle.addBuildListener(new BuildListener() {
//构建开始前调用
void buildStarted(Gradle var1) {
println '构建开始...'
}
//settings.gradle配置完后调用,只对settings.gradle设置生效
void settingsEvaluated(Settings var1) {
// var1.gradle.rootProject 这里访问 Project 对象时会报错,
// 因为还未完成 Project 的初始化。
println 'settings:执行settingsEvaluated...'
}
//当settings.gradle中引入的所有project都被创建好后调用,只在该文件设置才会生效
void projectsLoaded(Gradle var1) {
println 'settings:执行projectsLoaded...'
println '初始化结束,可访问根项目:' + var1.gradle.rootProject
}
//所有project配置完成后调用
void projectsEvaluated(Gradle var1) {
println 'settings: 执行projectsEvaluated...'
}
//在project进行配置前调用,child project必须在root project中设置才会生效,root project必须在settings.gradle中设置才会生效
void beforeProject { proj ->
println "settings:执行${proj.name} beforeProject"
}
//在project配置后调用
void afterProject { proj ->
println "settings:执行${proj.name} afterProject"
}
//构建结束后调用
void buildFinished(BuildResult var1) {
println '构建结束 '
}
})
看下输出结果:
settings:执行settingsEvaluated...
settings:执行projectsLoaded...
settings:执行GradleTestDemo beforeProject
根项目配置开始---
根项目里任务配置---
根项目配置结束---
settings:执行GradleTestDemo afterProject
settings:执行app beforeProject
子项目beforeEvaluate回调...
APP子项目配置开始---
APP子项目里任务配置---
APP子项目配置结束---
settings:执行app afterProject
APP子项目afterEvaluate回调...
settings: 执行projectsEvaluated...
构建结束...
另外还有其他监听方法:
this.gradle.beforeProject{} //等同于beforeEvaluate
this.graddle.afterProject{} //等同于afterEvaluate
//下面几种都是可以监听的
this.gradle.addListener
tthis.gradle.addProjectEvaluationListener
在了解了gradle的生命周期监听后,还有个疑问为什么执行build命令的时候,会其他命令的输出。下面我们来看一张图:
这张图会在配置阶段完成,形成一个有向无环图,在执行名字为build的task的时候,所以会有其他依赖的task都要执行完。
TaskExecutionGraph(Task执行图)
Gradle 在配置完成后,会对所有的 task 生成一个有向无环图,这里叫做 task 执行图,他们决定了 task 的执行顺序等。
TaskExecutionGraph API文档
下面是常用的API方法:
API | 描述 |
---|---|
addTaskExecutionGraphListener | 给任务执行图添加监听 |
addTaskExecutionListener | 给任务的执行添加监听 |
whenReady | 当任务执行图填充完毕被调用 |
beforeTask | 当一个任务执行之前被调用 |
afterTask | 当一个任务执行完毕被调用 |
hasTask | 查询是否有这个task |
getAllTasks | 获取所有的Task |
Set getDependencies(Task task) | 返回参数Task的依赖关系 |
同样,Gradle 可以对 task 的执行生命周期进行监听。
TaskExecutionGraph taskGraph = gradle.getTaskGraph()
taskGraph.whenReady {
println "task whenReady"
}
taskGraph.beforeTask { Task task ->
println "任务名称:${task.name} beforeTask"
}
taskGraph.afterTask { Task task ->
println "任务名称:${task.name} afterTask"
}