1 简介

Gradle是一款非常优秀的构建系统工具,它是一门专门解决自动化构建的DSL(Domain Specifice Language,领域特定语言)。它的实现基于Groovy(Groovy是一种基于JVM虚拟机的敏捷开发语言,它结合了Python、Ruby和Smalltalk的许多强大的特性,Groovy它的语法和Java非常相似,能够与 Java 代码很好地结合和扩展)。

2 环境

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命令查看即可(若不行请重启电脑)。

3 Hello World

新建一目录,如: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(全部堆栈信息)来打印出堆栈信息

4 Gradle Wrapper

Wrappe是对Gradle的一层包装,便于团队开发过程中统一Gradle构建的版本。当我们使用Wrapper启动Gradle时,Wrapper会检查Gradle有没有被下载关联,如果没有将会配置的地址(一般是Gradle官方库)进行下载并运行构建。只要执行Wrapper命令,它会帮你搞定一切。这种方式也方便我们在服务器上做持续集成。

4.1 生成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。

4.2 自定义Wrapper Task

也可以通过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'
}

5 Groovy关键语法

5.1 分号

Groovy中,分号是可写可不写的。

5.2 字符串

Groovy中,单引号和双引号都可以定义字符串常量,不同的是单引号标记的是纯粹字符串常量,而不是对字符串里的表达式做运算,但双引号可以。如使用“+”连接两个字符串,就一定得使用双引号。

5.3 集合

List

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

来看看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}";
	}
}

运行结果: 

5.4方法

方法的写法很有意思,括号是可以省略的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;
}

5.5 getter/setter

task hello{
	Person person = new Person()
	person.name = '子云心'
		
	println person.name
	println person.age
}
class Person {
	private String name;			// 私有变量也能被访问
	public int getAge() {			// 方法也可被直接当属性使用
		25;
	}
}

5.6 闭包(代码块)

一段被大括号包括的代码称为闭包或代码块。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<Delegate> 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来实现的,详细使用在后面介绍

6 任务

6.1 创建

Gradle创建任务的方式有多种

第一种,任务名字+闭包配置的方式(我们在上面看到的方式)

task hello{
	doLast{
		println'Hello World!'
	}
}


第二种,变量方式,task(String name)方法接收一个任务名作为参数,然后赋予变量

def Task taskHello = task(hello)
taskHello.doLast{
	println'Hello World!'
}

6.2 分组和描述

任务是可以分组的和添加描述的,这样就是便于我们对任务进行归类整理,建议大家在创建任务时都要进行这两个属性的配置,以便于团队开发时别人能清楚知道该任务的分类和用途。示例:

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!'
}

6.3 <<操作符

“<<”操作符在Gradle的Task上是doLast方法的知标记形式,所以上述示例也可以写成:

def Task taskHello = task(hello, group:BasePlugin.BUILD_GROUP, description:'我是hello任务')
taskHello <<{
	println'Hello World!'
}

6.4 任务顺序

通过shouldRunAfter和mustRunAfter两个方法可以控制一个任务应该或者一定在某个任务之后执行。

taskB. shouldRunAfter(taskA)          表示taskB应该在taskA执行之后执行,但这里是应该,所以有可能并不会按预设的执行

taskB. mustRunAfter (taskA)           表示taskB一定在taskA执行之后执行。

6.5 任务依赖

除了使用方法进行任务间改变执行顺序外,还可以使用任务依赖关系。示例:

task taskA << {
	println 'This is taskA'
}
task taskB(dependsOn: taskA) << {
	println 'This is taskB'
}
task taskC {
	dependsOn taskB				// 多个可用逗号分隔
	doLast {
		println 'This is taskC'
	}	
}

说明:

  1. 在创建taskB任务时,可通过dependsOn 指写其依赖的任务
  2. 在taskC任务执行时,也可以通过另外的方式让其依赖taskB
  3. 当执行命令:gradle –q taskC后,输出结果应该是:

This is taskA

This is taskB

This is taskC

 

 

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐