之前2节,主要是针对Groovy的语法进行了讲解,在Gradle脚本的编写中就会涉及这些语言特性,如果想要编写脚本,自定义Gradle插件,首先需要了解Gradle的构建过程。
Gradle构建和Task引入
1 Gradle工程层级结构
一个Gradle工程,不管是Android还是其他的工程,只要设计到Gradle,工程结果都是一样的
1 setting.gradle
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
jcenter() // Warning: this repository is going to shut down soon
maven {url 'https://jitpack.io'}
flatDir {
dirs 'app/libs'
}
}
}
rootProject.name = "Diandu" //当前Android主工程名 在
include ':app'
Gradle工程的根,Gradle编译时就是从setting.gradle开始解析,在初始化的时候会生成Setting对象,rootProject就是Setting中的getRootProject(),默认生成了get和set方法
ProjectDescriptor getRootProject();
Gradle是支持多工程构建的,在setting.gradle中可以配置子模块,使用include表示当前为一个子Moudle,每个模块名称前的 " : "代表是跟setting同级的模块
如果在lib文件夹下,有一个lib模块,就可以使用下面的方式拼接
include ':lib:mylib'
如果要引用当前工程之外的一个工程,做工程之间的相互依赖,可以配置依赖的moudle的路径
project(':MyApplication').projectDir = new File('../MyApplication')
2 gradlew.bat
gradle执行的脚本命令,可通过命令行运行gradle脚本
3 build.gradle
当seeting.gradle解析完成之后,就执行 build.gradle脚本,用于生成Project对象,task任务也是在这个阶段完成了配置
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath "com.android.tools.build:gradle:7.0.3"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.20"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
buildscript中的repositories为构建脚本依赖项添加仓库,也就是dependencies中的插件,像Android的gradle插件,Kotlin的gradle插件等
4 gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionUrl=https://services.gradle.org/distributions/gradle-7.0.2-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
用于为不同的设备统一版本,像distributionUrl中声明的gradle版本,在不同设备中,都会下载这个版本的gradle,其中gradle-7.0.2-bin.zip是二进制的发布版本,如果想要看gradle的源码,可以换成gradle-7.0.2-all.zip,其中就包含了gradle的源码
2 Gradle的生命周期
像Activity、Fragment一样,gradle也有自己的生命周期,可用于在编译阶段做对应的调度
2.1 初始化阶段
在初始化阶段,会执行setting.gradle脚本,是所有脚本执行的起始位置,在这个阶段,gradle会确定哪些模块会参与构建
其中在初始化阶段,有2个钩子函数,settingsEvaluated和projectsLoaded
gradle.settingsEvaluated {
println "settingsEvaluated"
}
gradle.projectsLoaded {
println "projectsLoaded"
}
gradle编译执行:
settingsEvaluated
projectsLoaded
> Configure project :
beforeProject
> Configure project :app
beforeProject
组件化
在初始化阶段,Configure之前,如果想要做处理,因为这个时候,project对象还没有生成,只能使用gradle,可以看出在配置阶段之前,这个两个钩子函数中的配置执行了
2.2 配置阶段
在配置阶段,会解析每个项目的build.gradle,生成project对象,同时会配置task但不会执行;
在配置阶段,钩子函数更多,除了gradle的钩子函数之外,还有Project的钩子函数
//对其全部子工程有效
gradle.beforeProject {
println 'gradle beforeProject'
}
//对当前工程有效
project.afterEvaluate {
println 'project afterEvaluate'
}
其中,gradle是对其全部子项目有效,对当前工程是无效的;而project只对当前工程有效,而对其子项目是无效的,因此可以使用gradle或者project按需配置工程
> Configure project :
task A Configure
project afterEvaluate
> Configure project :app
gradle beforeProject
组件化
> Configure project :business
gradle beforeProject
这里需要注意一点,如果要对全部的子工程配置,只能在根工程的build.gradle中进行脚本配置;
2.3 执行阶段
在这个阶段,就会真正地执行task任务,那么下面就开始介绍gradle中的task任务
3 Task任务
gradle中的task任务,其实在整个项目创建之后,在build.gradle中就有一个task
task clean(type: Delete) {
delete rootProject.buildDir
}
这个是一个清除任务,将build文件夹清除,然后重新编译后的生成新的build文件夹
3.1 task基础
创建一个A任务
task A{
}
在Android Studio右侧的Task任务栏中,other文件夹下,就有这个A任务,直接双击就可以执行这个A任务
task A{
println "task A"
}
task B{
println 'task B'
}
task C(dependsOn:[A,B]){
println 'task C'
}
在Task中,任务的排序是按照首字母的顺序,如果C任务依赖任务A和任务B,那么可以使用dependsOn属性声明
3.1.1 任务的执行顺序
默认情况下,就是按照任务首字母的顺序执行,像C依赖A和B,必须要等到A和B执行完成之后,才可以执行C;如果想要B先执行,那么可以通过mustRunAfter,来设置B先执行,然后A后执行
A.mustRunAfter B
> Task :B UP-TO-DATE
> Task :A
> Task :C
但是如果存在依赖关系,想要B在C之后执行显然是不可能的!
还有一个API是shouldRunAfter,这种就不是强制性的,不一定A是在B之后执行
3.1.2 doFirst doLast
在配置阶段,是不会执行task中的action的,只有在执行阶段才会执行,那么doFirst和doLast就是Action方法
C.doFirst {
println "C do First"
}
C.doLast {
println "C do doLast"
}
A.doFirst {
println "A do First"
}
任务执行输出:
> Task :A
A do First
> Task :C
C do First
C do doLast
3.1.3 资源回收
当一个任务执行完成之后,需要对无用资源回收,可以使用finalizedBy
task finalizeTask{
println '资源回收'
}
A.finalizedBy finalizeTask
> Task :B UP-TO-DATE
> Task :A
A do First
> Task :finalizeTask UP-TO-DATE
> Task :C
C do First
C do doLast
我们可以看到当任务A执行完成之后,立刻执行了资源回收任务
3.2 自定义Task
打印每个Task的class,发现每个Task都是DefaultTask类型,自定义Task也是以DefaultTask为基类
class org.gradle.api.DefaultTask_Decorated
class MyTask extends DefaultTask{
MyTask(){
group 'custome'
println 'MyTask 构造方法 配置阶段执行'
}
@TaskAction
def Action(){
println 'MyTask 执行了'
}
}
tasks.create('MyTask',MyTask){
//执行Action中的方法
it.Action()
}
自定义Task继承自DefaultTask,在构造方法中可以做初始化,这部分是在配置阶段完成的,之前讲到自己创建的task默认是放在other分组中,如果想单独放在一个分组中,可以使用group分组
3.2.1 自定义Task的创建方式1 — tasks.create
使用tasks.create可以创建自定义的task任务,第一个参数为创建的Task名称,
第二个参数为Task任务的类型,即自定义的任务,在闭包当中可以调用自定义Task中的TaskAction方法
3.2.2 自定义Task的创建方式2 ---- task
task customTask(type: MyTask){
Action()
}
这种方式才是主流的创建方式,类似于build.gradle中的清除任务,通过type声明任务的类型,可以直接调用MyTask中的TaskAction方法
> Task :customTask
MyTask 执行了
task是Project中的task,因此每个脚本的执行都必须依赖Project对象,因此在创建一个build.gradle文件之后,这个脚本是不能单独运行的,因为它没有被解析生成对应的Project对象,必须通过apply from 依赖到某个build.gradle中
总结
写到这里也结束了,在文章最后放上一个小小的福利,以下为小编自己在学习过程中整理出的一个关于 java开发 的学习思路及方向。从事互联网开发,最主要的是要学好技术,而学习技术是一条慢长而艰苦的道路,不能靠一时激情,也不是熬几天几夜就能学好的,必须养成平时努力学习的习惯,更加需要准确的学习方向达到有效的学习效果。
由于内容较多就只放上一个大概的大纲,需要更及详细的学习思维导图的 点击我的Gitee获取。
还有 高级java全套视频教程 java进阶架构师 视频+资料+代码+面试题!
全方面的java进阶实践技术资料,并且还有技术大牛一起讨论交流解决问题。