电子说
大家回想一下自己第一次接触Gradle
是什么时候?
相信大家也都是和我一样,在我们打开第一个AS项目的时候,
发现有很多带gradle字样的文件:setting.gradle, build.gradle,gradle.warpper
,以及在gradle
文件中各种配置,
这些都是啥wy啊。。
特别对于一些小公司开发人员,因为接触架构层面的机会很少,可能在使用AS几年后都不一定对Gradle
有太多深入了解,这是实话,因为笔者就是这么过来的。。
而Gradle
又是进阶高级
开发的必经之路。
好了,接下来进入正题,此系列笔者会由浅入深的方式,带领大家来了解下,Gradle
背后究竟有哪些奥秘。
Gradle
定义:很多开发喜欢把Gradle
简单定义为一种构建工具,和ant,maven
等作用类似,
诚然Gradle确实是用来做构建,但是如果简单得把Gradle拿来做构建,就太小看Gradle了.
笔者更愿意将Gradle看做一种编程框架
。在这个框架中,你可以做很多ant,maven等常用构建工具做不了的事情,
如将自己的任务task集成到构建生命周期中,完成文件拷贝,脚本编写等操作。
Gradle
优缺点:相较早期的构建工具:ant,maven等。
1.使用DSL Grovvy语言来编写: :了解ant的同学应该都知道:ant使用的是xml配置的模式,而Gradle使用的是表达性的Groovy
来编写,
Groovy同时支持面向对象和面向过程
进行开发,这个特性让Groovy
可以写出一些脚本的任务,这在传统ant,maven上是不可能实现的
2.基于java虚拟机: :Groovy
是基于jvm
的语言,groovy
文件编译后其实就是class文件,和我们的java
一样。
所以在gradle构建过程中,我们完全可以使用java/kotlin去编写我们的构建任务以及脚本,极大的降低我们学习的成本。
生命周期
中去,这在ant,maven上也是不可能实现的,关于Groovy的语法篇:可以参考这篇文章:
Gradle筑基篇(二)-groovy语法详解
用过gradle都知道,低版本gradle的项目在高版本的gradle中经常出现很多莫名其妙的错误,向后兼容性较差。
Gradle
工程结构:gradle标准工程代码如下
├── moduleA
│ └── build.gradle
├── moduleB
│ └── build.gradle
├── build.gradle
├── settings.gradle
├── gradle.properties
├── local.properties
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
└── gradlew.bat
build.gradle
:可以理解为一个Project脚本,Project脚本中有自己的任务,最外层的Project为rootProjectsettings.gradle
:主要用来配置我们项目中需要用到的模块。用include关键字给包裹进gradle.properties
:这个文件主要是设置一些全局变量,包括jvm运行以及自定义的一些全局参数local.properties
:这个文件主要配置一些本地的sdk和ndk版本信息以及路径gradle-wrapper.jar
:负责自动下载Gradle脚本运行环境gradle-wrapper.properties
:用来配置当前使用的Gradle的版本以及存储的路径distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\\://services.gradle.org/distributions/gradle-6.5-bin.zip
distributionBase + distributionPath:指定Gradle安装路径;
zipStoreBase + zipStorePath:指定Gradle安装包的存储路径;
distributionUrl:Gradle版本的下载地址。
注意这里如果将bin改为all,则可以查看当前Gradle的源码信息。
gradlew和gradlew.bat
:用来执行构建任务的脚本,可以在命令行使用gradlew xxxTaskGradle作为新兴的构建工具,其内部也有自己的生命周期阶段,每个阶段做的事情都层次分明,
了解Gradle生命周期,才能很好的使用我们的Gradle工具。
做了哪些事情?:
Setting.gradle
文件,获取setting
实例,setting
中的脚本,根据include
字段,创建对应的project
实例注意:初始化阶段执行任何任务都会执行一次。
Project实例关系如下:
gradleproject树.png
build.gradle
文件中的脚本信息有向无环图
,防止任务执行进入死循环。注意:配置阶段执行任何任务都会执行一次。
执行阶段就是根据当前task拓扑图进行执行task任务。
需要注意以下几点:
1.在项目中配置的doLast,doFirst
操作,都会在任务执行阶段执行,而不会在配置阶段执行,
而如果任务需要执行,需要挂接到gradle执行生命周期
中,笔者开始接触gradle时就踩过这个坑。。这块后面讲解task
的时候在来具体讲解
2.前面也说了初始化阶段和配置阶段在每个任务执行前都会执行,所以 不要在前两个阶段进行一些耗时的操作 ,这样可能每次编译执行你都会崩溃的
要查找Gradle是如何监听生命周期,可以到Gradle
源码中看看:
1.监听初始化阶段
初始化阶段主要用来初始化Setting.gradle
文件,获取setting
实例,创建Project
实例等,所以其可用下面代码监听:
//开始初始化Setting.gradle前
this.gradle.beforeSettings {
println "beforeSettings"
}
//Setting.gradle配置完毕后,创建了setting实例
this.gradle.settingsEvaluated {
println "settingsEvaluated"
}
//执行解析Setting.gradle文件后,创建了project实例列表
this.gradle.projectsLoaded {
println "projectsLoaded"
}
2.1:监听当前project的配置阶段前后:
在Project源码
中可以看到:
/**
* Adds an action to execute immediately before this project is evaluated.
*
* @param action the action to execute.
*/
void beforeEvaluate(Action? action);
/**
* Adds an action to execute immediately after this project is evaluated.
*
* @param action the action to execute.
*/
void afterEvaluate(Action? action);
/**
* Adds a closure to be called immediately before this project is evaluated. The project is passed to the closure
* as a parameter.
*
* @param closure The closure to call.
*/
void beforeEvaluate(Closure closure);
/**
* Adds a closure to be called immediately after this project has been evaluated. The project is passed to the
* closure as a parameter. Such a listener gets notified when the build file belonging to this project has been
* executed. A parent project may for example add such a listener to its child project. Such a listener can further
* configure those child projects based on the state of the child projects after their build files have been
* run.
*
* @param closure The closure to call.
*/
void afterEvaluate(Closure closure);
看这两个方法的说明就是用来监听配置阶段,传入的是一个Action或者传入一个闭包,闭包的代理为当前Project
使用方式如下 :
//监听project被配置前
this.beforeEvaluate {Project project ->
println "${project.name} :beforeEvaluate"
}
//监听project被配置后
this.afterEvaluate {Project project ->
println "${project.name}:afterEvaluate"
}
注意:这个监听只是针对当前Project的配置阶段而不是所有Project的配置
你也可以使用:
this.project.beforeEvaluate
this.project.afterEvaluate
那么有没有可以监听所有Project的配置阶段的api呢?安排
2.2:监听每个Project的配置前后:
使用this.gradle的内部方法,因为gradle是相对于整个工程作为作用域
//监听所有的Project的被配置前
this.gradle.beforeProject {Project project ->
println "${project.name}:beforeProject"
}
//监听所有的Project的被配置后
this.gradle.afterProject {Project project ->
println "${project.name}:afterProject"
}
编译下看看:
> Configure project :
gradle_source_plugin:afterProject
> Configure project :app
app:beforeProject
do app evaluating
app:afterProject
> Configure project :application
application:beforeProject
do application evaluating
application:afterProject
看到当前工程所有的project都调用了一次beforeProject和afterProject
那有同学又要问了,有没有监听整个project配置阶段的:当然有
2.3:监听全部project配置阶段的前后
this.gradle.projectsEvaluated {
println "all projectsEvaluated"
}
这个闭包可以监听整个项目的配置完毕后的事件
配置阶段还有一些监听如下:
2.4:监听任务的添加操作
this.project.tasks.whenTaskAdded {Task task->
println "${task.name}:whenTaskAdded"
}
2.5:监听任务拓扑图的执行
//task拓扑图构造完毕
this.gradle.taskGraph.whenReady {TaskExecutionGraph graph->
println "taskGraph:->"+graph
}
监听拓扑图完毕后其实才是真正的配置阶段完毕 ,瞧瞧源码:
在BasePlugin中:
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_CONFIGURE,
project.getPath(),
null,
this::configureProject);
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_BASE_EXTENSION_CREATION,
project.getPath(),
null,
this::configureExtension);
threadRecorder.record(
ExecutionType.BASE_PLUGIN_PROJECT_TASKS_CREATION,
project.getPath(),
null,
this::createTasks);
看到配置阶段最后一步才是创建Task,所以可以使用this.gradle.taskGraph.whenReady监听整个配置阶段的结束
3.1:监听任务执行:
gradle.taskGraph.beforeTask { Task task ->
println "${task.name}:beforeTask"
}
gradle.taskGraph.afterTask {Task task ->
println "${task.name}:afterTask"
}
执行下面任务:
task clean(type: Delete) {
doFirst {
println 'clean:doFirst'
}
doLast {
println 'clean:doLast'
}
delete rootProject.buildDir
}
结果:
> Task :clean
clean:beforeTask
clean:doFirst
clean:doLast
clean:afterTask
可以看到在task执行前后调用了监听中的方法
3.2:监听执行任务阶段开始
其实可以使用配置阶段的this.gradle.taskGraph.whenReady,这个就是所有project配置完毕,且生成了task拓扑图
下一步就是开始执行任务了
3.3:监听执行任务阶段结束
this.gradle.buildFinished {}
这个可以监听所有任务执行完毕后事件回调:
全部0条评论
快来发表一下你的评论吧 !