一.Gradle
(一)简介
Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建工具,是一个基于JVM的构建工具,支持maven, Ivy仓库,支持传递性依赖管理,而不需要配置文件,其脚本的编写是一种基于Groovy的特定领域语言(DSL)。
(二)项目结构
通过上图AndroidStudio为我们自动创建的项目结构,可以发现,一个项目中可以有多个的子项目的存在,那么对于这种情况gradle是如何进行项目构建的呢:
-
蓝色:我们的根项目是KotlinApplication,其下有两个子项目,分别说主项目app,和子项目subproject1
-
红色:红色的三个build.gradle,是项目自动生成的,app和subproject1目录下的build.gradle文件,就是构建相应项目的脚本文件,也就是说每个项目有自己的构建脚本;而KotlinApplication目录下的build.gradle文件,是针对于整个项目的构建脚本,他用于对整个项目的构建做一些操作
-
黄色:黄色的settings.gradle,位于根项目目录下,是用来配置有哪几个项目的脚本文件
//settings.gradle include ':app', ':subproject1'
代表项目中有app、subproject1两个子项目需要进行构建,配置后,相应项目的build.gradle脚本文件在构建时就会被执行
-
绿色:绿色的两个文件gradlew和gradlew.bat,是用来执行gradle命令的,gradlew即gradle wrapper缩写,用于兼容不同版本的gradle所提供的命令行脚本文件,而bat则是用在win系统上的脚本文件,所以我们在使用gradle命令时,通常都是./gradlew xxx的形式,执行的就是该文件对应的命令
除此之外,build.gradle文件执行的project就是包含其的目录,该目录下的内容对应的就是一个Project对象,而且gradle还提供了构件时的临时文件夹,用于存放构建产生的文件,位置就在其对应project目录下的build文件夹:比如执行app下的build.gradle,其project对应的就是app,而app的build文件夹就在app/目录下
以上就是gradle为构建项目提供的目录结构
(三)基本概念
-
Project:每个gradle脚本会将构建的项目,抽象为一个Project对象,包含有项目相关的一些信息和操作
-
Task:gradle认为每个project的构建过程,其实是由一个一个的任务完成,比如依赖的引入、资源的打包等等,而将每一个任务抽象为一个Task对象
-
Plugin:Plugin为一个插件对象,用于完成一个模块的功能,每个Plugin可以对project进行整体的操控,比如引入依赖、执行task等等,是对一组Task的封装
-
Dependencies:每个project都可以引入第三方的一些库(功能),称为依赖,包括不同网站上的、本地的项目等等,gradle将其抽象为Dependencies对象
(四)脚本执行过程
当我们使用gradlew命令执行一个task时,gradle会先通过settings.gradle文件中指定的项目,创建处相应的Project对象,然后依次执行其build.gradle文件,执行build.gradle文件,其实会分为两个阶段:
1.配置阶段
对于一个gradle脚本文件,会依次扫描其语句,然后执行配置期的语句,比如:创建Task/Plugin对象、调用其初始化方法、执行Task的定义期语句、执行configure方法进行自定义配置等,而真正的执行内容不会再该阶段执行
2.执行阶段
当配置阶段完成后,会按照定义,执行相应Task的执行方法完成工作,不依赖于脚本的定义顺序
以上这些执行过程,在下面的讲解中再具体说明
二.Task
(一)创建
对于创建Task的方式,先来看一中最常用的方式:
task HelloWorld << {
println 'Hello World!' }
该Task在执行时会输出Hello World!
其实,是gradle脚本使用的基于groovy的DSL语言帮助我们如此快捷的实现一个Task的定义,其实质上是“啰嗦”的方法调用的简写:
project.tasks.create('HelloWorld').doLast(new Closure() {
...})
由代码可知,其本质上其实就是调用了当前project对象的TaskContainer(一个Project包含的所有Task的对象)的create方法,传入一个字符串作为Task的name,然后调用doLast()方法,传入一个闭包对象用于设置task的执行代码,但是通过DSL语言我们就可以非常简单的方式书写了(因为闭包有代理对象,可以不用声明调用者;再加上groovy调用方法时可以再方法名后直接跟参数),所以一下几种方式创建Task是一样的(但是写法上逐步简化):
project.tasks.create('HelloWorld').doLast {
println 'Hello World!'
}
project.task('HelloWorld').doLast {
println 'Hello World!'
}
task HelloWorld << {
println 'Hello World!'
}
(二)定义执行代码
上面是定义Task对象,在扫描阶段,会创建相应的Task类的对象,那么如何定义其要执行的代码呢?gradle提供了几种常用的方式向Task插入代码
1.配置阶段代码
在定义Task时直接定义的语句,会被认为是配置阶段的代码,在扫描gradle文件构建Task对象后会立刻执行
task HelloWorld {
println 'Hello World!'
}
如上代码,在执行该Task时,在扫描脚本文件阶段就会执行,输出Hello World!
2.doFirst
为task定义doFirst执行体,在运行阶段执行task时,会先执行该段代码
task HelloWorld {
doFirst {
println 'task run first'
}
}
如上代码,在运行阶段执行该task时,会输出task run first
3.doLast
对应doFirst,也有doLast方法,我们在定义阶段的<<符号为doLast的简写方式,即在运行阶段执行task时,会最后执行该段代码,为了验证这几几种方法的执行顺序,我们来举一个例子
task HelloWorld {
doLast {
println 'task run last'
}
doFirst {
println 'task run first'
}
println