破解Gradle(三) Gradle构建生命周期

Android Studio默认的工具是Gradle,通常开发者不需要了解Gradle的脚本配置,也能开发出一个App,但是如果你需要修改打包中的输出目录、提高打包速度的话,就要对Gradle有个深入的了解了。而在开发学习Gradle不能仅仅把它当做一个工具来学习,更应该把它当成编程框架来看,这里是Gradle API文档,我们再编写编译脚本,其实就是在玩 Gradle的API。

Gradle的组成可以分为三部分:

  1. groovy核心语法
  2. Build script block
  3. Gradle API:包含project、Task/Settiing等等,也是接下来重点介绍的。

Gradle优势

  1. 在灵活性上,Gradle支持基于groovy语言编写脚本,侧重于构建过程的灵活性,适合于构建复杂度较高的项目,可以完成非常复杂的构建。
  2. 在粒度性上,Gradle 构建的粒度细化到了每一个 task 之中。并且它所有的 Task 源码都是开源的,在我们掌握了这一整套打包流程后,我们就可以通过去修改它的 Task 去动态改变其执行流程。
  3. 在扩展性上,Gradle 支持插件机制,所以我们可以复用这些插件,就如同复用库一样简单方便。

Grale 构建生命周期

下面来看下gradle的执行命令,执行./gradlew build 可以说是最复杂的task命令了。 (./gradlew是mac中的语法)

image-20220108201559635可以看到每次都会执行很长时间,是因为build的task任务依赖了很多任务,它会把它所依赖的task执行完之后,才会执行自己的task.。我们还是先了解下Gradle的构建过程。

Gradle的构建过程可以分为三部分:初始化阶段配置阶段执行阶段

image-20220108234033023

初始化阶段

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命令的时候,会其他命令的输出。下面我们来看一张图:

image.png

这张图会在配置阶段完成,形成一个有向无环图,在执行名字为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"
}

参考

深入理解Android之Gradle

深度探索 Gradle 自动化构建技术(三、Gradle 核心解密)

看完这一系列,彻底搞懂 Gradle

Gradle基础 - 构建生命周期和Hook技术

Gradle构建生命周期

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值