破解Gradle Gradle构建生命周期

Posted 丶笑看退场

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了破解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中的语法)

可以看到每次都会执行很长时间,是因为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"

参考

深入理解Android之Gradle

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

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

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

Gradle构建生命周期

以上是关于破解Gradle Gradle构建生命周期的主要内容,如果未能解决你的问题,请参考以下文章

Android Gradle 插件Gradle 构建生命周期 ② ( Gradle 类的添加构建生命周期监听器函数 | Gradle#addListener 函数 )

Android Gradle 插件Gradle 构建机制 ④ ( Gradle 构建生命周期 | 初始阶段 | 配置阶段 | 执行阶段 )

Android Gradle 插件Gradle 构建生命周期 ① ( 分析构建脚本 | 执行初始化配置 | 执行 Gradle 任务 | Project#beforeEvaluate 函数 )

Gradle生命周期

Android Gradle 插件Gradle 构建生命周期 ③ ( BuildListener 构建监听器 | TaskExecutionGraphListener 任务执行图监听器 )

Gradle 庖丁解牛(构建生命周期核心委托对象创建源码浅析)