Gradle是一款非常优秀的构建系统工具,它是一门专门解决自动化构建的DSL(Domain Specifice Language,领域特定语言)。它的实现基于Groovy(Groovy是一种基于JVM虚拟机的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy它的语法和Java非常相似,能够与 Java 代码很好地结合和扩展)。
Gradle的官网下载页地址是:https://services.gradle.org/distributions/。一般地下载完后将其解压放于C:\Program Files\Android\gradle-x.x.x中,我们可以看到如下目录清单:
bin
docs -- API、DSL、指南等文档
init.d -- gradle的初始化脚本目录
lib -- 相关库
media -- 一些icon资源
samples -- 示例
src -- 源文件
getting-started.html -- 入门链接
LICENSE
NOTICE
要运行Gradle,必须把bin目录添加到环境变量PATH的路径里才可以。添加后要验证配置是否正常,我们只需要在命令窗口中输入gradle –v命令查看即可(若不行请重启电脑)。
新建一目录,如:gradle_hello_world,然后就该目录下创建一个名为build.gradle的文件,文件内容如下:
task hello{
doLast{
println'Hello World!'
}
}
命令窗口中运行gradle –q hello命令来执行构造脚本,输出:
说明:
1、build.gradle就Gradle默认的构建脚本,执行Gradle命令时会默认加载当前目录下的build.gradle脚本文件。
2、这个脚本定义一个任务(Task),任务名叫hello,并且给任务hello添加一个动作(Action),其实它就是一段Groovy语言实现的闭包。doLast意味着在Task执行完毕后要回调doLast的这部分闭包的代码实现。
3、因为Groovy已经把println()方法添加到java.lang.Object,而在Groovy中,方法的调用可省略括号,以一个空格分开即可;还有一点,在Groovy中单引号和双引号的内容都是字答串,不区分字符和字符串,但是单引号标记的是纯粹字符串常量,而不能参与表达式运算。
4、命令gradle –q hello中,-q参数用于控制gradle输出的日志级别。gradle的日志级别有:
ERROR 错误信息
QUIET 重要消息
WARNING 警告消息
LIFECYCLE 进度消息
INFO 信息消息
DEBUG 调试信息
5、另外,除了日志级别参数外,还可以通过-s(关键性的堆栈信息)或-S(全部堆栈信息)来打印出堆栈信息
Wrappe是对Gradle的一层包装,便于团队开发过程中统一Gradle构建的版本。当我们使用Wrapper启动Gradle时,Wrapper会检查Gradle有没有被下载关联,如果没有将会配置的地址(一般是Gradle官方库)进行下载并运行构建。只要执行Wrapper命令,它会帮你搞定一切。这种方式也方便我们在服务器上做持续集成。
在命令窗口中输入:gradle wrapper(默认当前电脑版本) 或 gradle wrapper –gradle-version x.x(指定版本),便生成如下图文件:
文件说明:
文件gradlew和gradlew.bat分别是Linux和Windows下的可执行脚本,它们的用法和Gradle原生命令是一样的。
文件夹gradle下有两件文件:gradle\wrapper\gradle-wrapper.jar 和 gradle\wrapper\gradle-wrapper.properties。其中,gradle-wrapper.jar是具体业务逻辑实现的jar包,gradlew最终还是使用Java执行这个jar包来执行相关Gradle操作,而gradle-wrapper.properties是配置文件,用于配置Gradle信息。
gradle-wrapper.properties它的内容如下图所示:
配置中字段说明:
distributionBase 下载的Gradle压缩包解压后存储的主目录
distributionPath 相对于distributionBase的解压后的Gradle压缩包的路径
zipStoreBase 同distributionBase,只不过是存放zip压缩包的
zipStorePath 同distributionPath,只不过是存放zip压缩包的
distributionUrl Gradle发行版压缩包的下载地址。通常地会将distributionUrl 中的bin改为all,这样在开发过程中,就可以看到Gradle的源代码。另外,如若总是下载失败,可以考虑将https替换成http。
也可以通过task来自定义gradle-wrapper.properties的字段信息,如个修改build.gradle文件,并运行命令:gradle wrapper
task hello{
doLast{
println'Hello World!'
}
}
task wrapper(type:Wrapper) {
gradleVersion = '4.2.1'
archiveBase='GRADLE_USER_HOME'
archivePath='wrapper/dists'
distributionBase='GRADLE_USER_HOME'
distributionPath='wrapper/dists'
distributionUrl='http://services.gradle.org/distributions/gradle-4.2.1-all.zip'
}
Groovy中,分号是可写可不写的。
Groovy中,单引号和双引号都可以定义字符串常量,不同的是单引号标记的是纯粹字符串常量,而不是对字符串里的表达式做运算,但双引号可以。如使用“+”连接两个字符串,就一定得使用双引号。
Groovy中,使用ArrayList就像使用普通数组一样,修改hello world示例代码如下:
task hello{
println'Hello World!'
def numList = [1,2,3,4,5];
println'----------ArrayList class name:'
println numList.getClass().name;
println'----------ArrayList element:'
println numList[1] // 访问第二个元素
println numList[-1] // 访问最后一个元素
println numList[0..2] // 访问第1到第3个元素
println'----------ArrayList each:'
numList.each{
println it;
}
}
运行结果:
来看看map的使用示例,同样修改hello world示例代码如下:
task hello{
println'Hello World!'
def mapSizp = ['width':1920, 'height': 1080];
println'----------LinkedHashMap class name:'
println mapSizp.getClass().name;
println'----------LinkedHashMap element:'
println mapSizp['width'];
println mapSizp.height;
println'----------LinkedHashMap each:'
mapSizp.each{
println "Key:${it.key},Value:${it.value}";
}
}
运行结果:
方法的写法很有意思,括号是可以省略的,return可写可不写,请看示例:
task hello{
println'Hello World!'
def a = compute(1, 2)
println a
def b = compute 3, 4
println b
}
def compute(int a, int b) {
// return a + b;
a + b;
}
task hello{
Person person = new Person()
person.name = '子云心'
println person.name
println person.age
}
class Person {
private String name; // 私有变量也能被访问
public int getAge() { // 方法也可被直接当属性使用
25;
}
}
一段被大括号包括的代码称为闭包或代码块。Groovy中是允许其作为参数传递的,像上面使用到的集合each方法为例,它接收的参数其实就是一个闭包:
// 呆板的写法
numList.each({ println it })
// 格式化后
numList.each( {
println it
})
// 如果方法的最后一个参数是闭包,可以放在方法外面
numList.each() {
println it
}
// 方法是可以省备括号的
numList.each {
println it
}
来自定义一个闭包作参数传递的示例:
task hello{
customEach {
println it
}
}
def customEach(closure) {
for(int i in i..10) {
closure(i)
}
}
说明:
当定义的方法只接收一个参数,用于接收一个闭包时,那么就可以默认使用it变量
向闭包传递参数示例:
task hello{
customEach2{k, v ->
println "${k} is ${v}"
}
}
def customEach2(closure) {
def mapSize = ["width":1920, "height":1080]
mapSize.each {
closure(it.key, it.value);
}
}
说明:
当闭包需要传递参数时,就不再使用it了,必须显式声明出来。
Groovy的闭包有thisObject、owner、delegate三个属性,当闭包内调用方法时,由它们来确定使用哪个对象来处理。示例:
task hello{
new Delegate().test {
println "thisObject:${thisObject.getClass()}"
println "owner:${owner.getClass()}"
println "delegate:${delegate.getClass()}"
methodl();
it.methodl();
}
}
def methodl() {
println "Context this:${this.getClass()} in root"
}
class Delegate {
def methodl() {
println "Delegate this:${this.getClass()} in Delegate"
}
def test(Closure closure) {
closure(this)
}
}
输出结果:
thisObject:class build_eglgh8qvzzqz0eqp07enfojra
owner:class build_eglgh8qvzzqz0eqp07enfojra$_run_closure1
delegate:class build_eglgh8qvzzqz0eqp07enfojra$_run_closure1
Context this:class build_eglgh8qvzzqz0eqp07enfojra in root
Delegate this:class Delegate in Delegate
说明:
thisObject的优先级最高,delegate和owner是相等的,但owner要比delegate优化级高。
delegate是可以被修改的,Gradle中的闭包很多功能都是通过修改delegate来实现的,详细使用在后面介绍
Gradle创建任务的方式有多种
第一种,任务名字+闭包配置的方式(我们在上面看到的方式)
task hello{
doLast{
println'Hello World!'
}
}
第二种,变量方式,task(String name)方法接收一个任务名作为参数,然后赋予变量
def Task taskHello = task(hello)
taskHello.doLast{
println'Hello World!'
}
任务是可以分组的和添加描述的,这样就是便于我们对任务进行归类整理,建议大家在创建任务时都要进行这两个属性的配置,以便于团队开发时别人能清楚知道该任务的分类和用途。示例:
def Task taskHello = task(hello)
taskHello.group = BasePlugin.BUILD_GROUP
taskHello.description = '我是hello任务'
taskHello.doLast{
println'Hello World!'
}
或者
def Task taskHello = task(hello, group:BasePlugin.BUILD_GROUP, description:'我是hello任务')
taskHello.doLast{
println'Hello World!'
}
“<<”操作符在Gradle的Task上是doLast方法的知标记形式,所以上述示例也可以写成:
def Task taskHello = task(hello, group:BasePlugin.BUILD_GROUP, description:'我是hello任务')
taskHello <<{
println'Hello World!'
}
通过shouldRunAfter和mustRunAfter两个方法可以控制一个任务应该或者一定在某个任务之后执行。
taskB. shouldRunAfter(taskA) 表示taskB应用在taskA执行之后执行,但这里是应该,所以有可能并不会按预设的执行
taskB. mustRunAfter (taskA) 表示taskB一定在taskA执行之后执行。
除了使用方法进行任务间改变执行顺序外,还可以使用任务依赖关系。示例:
task taskA << {
println 'This is taskA'
}
task taskB(dependsOn: taskA) << {
println 'This is taskB'
}
task taskC {
dependsOn taskB // 多个可用逗号分隔
doLast {
println 'This is taskC'
}
}
说明:
This is taskA
This is taskB
This is taskC