Settings 文件
在 Gradle 中,定义了一个设置文件,用于初始化以及工程树的配置。设置文件的默认名字是 settings.gradle ,放在根工程目录下。设置文件大多数的作用都是为了配置子工程。在 Gradle 中多工程是通过工程树表示的,就相当于我们在 Android Studio 看到的 Project 和 Module 概念一样。根工程相当于 Android Studio 中的 Project,一个根工程可以有很多子工程,也就是很多 Module ,这样就和 Android Studio 定义的 Module 概念对应上了。一个子工程只有在 Settings 文件里配置了 Gradle 才会识别,才会在构建的时候被包含进去。
rootProject.name = 'GradleTest'
include ':example02'
project(':example02').projectDir = new File(rootDir, 'chapter01/example02')
上例这就是我们示例工程的 setting 配置,可以看到我定义了很多子项目,并且为它们指定了相应的目录,如果不指定,默认目录是其同级的目录。比如 include: example02,如果我不指定, Gradle 就会把当前同级的 example02 目录作为 example02 工程的目录,但是没有这个目录,就会报错。利用这个特性,我们可以把我们的工程放到任何目录下,可以非常灵活地对我们的工程进行分级、分类等,只要 Settings 文件里指定好路径就可以了。
Build 文件
每个 Project 都会有一个 Build 文件,该文件是该 Project 构建的入口,可以在这里针对该 Project 进行配置,比如配置版本,需要哪些插件,依赖哪些库等。既然每个 Project 都会有一个 Build 文件,那么 Root project 也不例外。 Root project 可以获取到所有的 Child Project,所以在 Root Project 的 Build 文件里我们可以对 Child Project 统一配置,比如应用的插件,依赖的 Maven 中心库等。
Projects 以及 tasks
在 Gradle 中,可以有很多 Project ,你可以定义创建一个 Project 用于生成一个 jar,也可以定义另外一个 Project 用于生成一个 war 包,还可以定义一个 Project 用于发布上传你的 war 等。其实一个 Project 就是在你的业务范围内,被你抽象出来的一个个独立的模块,你可以根据项目的情况抽象归类,最后这一个个的 Project 组成了你的整个 gradle 构建。从我们编程的角度讲,它就是一个个独立的模块。好好利用它们,这样你的代码就能够做到低耦合、高内聚。
一个 Project 又包含很多个 Task ,也就是说每个 Project 是由多个 Task 组成的。Task 就是一个操作,一个原子性的操作,比如打个 jar 包,复制一份文件,编译一次 Java 代码,上传一个 jar 到 Maven 中心库等,这就是一个 Task ,和 Ant 里的 Target, Maven 中的 goal 是一样的。
创建一个任务
task customTask {
doFirst {
println 'customTask:doFirst'
}
doLast {
println 'customTask:doLast'
}
}
这里的 Task 看着像一个关键字,其实它是 Project 对象的一个函数,原型为 create(Sting name, Closure configure Closure)。 customTask 为任务的名字,我们可以自定义;第二个参数是个闭包,也就是我们花括号里的代码块。根据我们前面讲的 Groovy 知识,最后一个参数是闭包的时候,可以放到括号外面,然后方法的括号可以省略,就生成了我们上面的写法,很简洁。该闭包的作用就是用来对我们创建的任务进行配置,例子中我们用了任务的 dofirst 和 dolast 方法,分别在任务执行前后输出一段文字。
除了上面的方法,我们还可以通过 TaskContainer 创建任务。在 Gradle 中,Project 对象已经帮我们定义好了一个 TaskContainer ,就是 tasks 。
tasks.create ('customTask2'){
doFirst {
println 'customTask:doFirst'
}
doLast {
println 'customTask:doLast'
}
}
这种创建任务的方法跟上一种效果是一样的,只是名字不一样。
任务依赖
任务之间是可以有依赖关系的,这样我们就能控制哪些任务先于哪些任务执行;哪些任务执行后,其他任务才能执行。比如我们运行 jar 任务之前, compile 任务一定要执行过,也就是 jar 依赖于 compile ; Android 的 install 任务一定要依赖 package 任务进行打包生成 apk ,然后才能 install 设备里。
task test2 << {
println 'test2'
}
task test(dependsOn: test2){
doLast {
println 'test'
}
}
在创建任务的时候,通过 dependsOn 可以指定其依赖的任务。
task test2 << {
println 'test2'
}
task test(dependsOn: test2){
doLast {
println 'test'
}
}
task test3 {
dependsOn test,test2
doLast {
println 'test3'
}
}
dependsOn 是 Task 类的一个方法,可以接收多个依赖的任务作为参数。同时我们也可以使用 Task 的 API 访问它的方法属性或者对任务重新配置。
task ex36Hello << {
println 'dowLast1'
}
ex36Hello.doFirst {
println 'dowFirst'
}
ex36Hello.doLast {
println project.hasProperty('ex36Hello')
println 'dowLast2'
}
和变量一样,要使用任务名操纵任务,必须先定义声明,因为脚本是顺序执行的。运行上述代码后:

由结果可知,Project 在创建任务的时候,同时把该任务对应的任务名注册为 Project 的一个属性,类型是 Task 。
自定义属性
Project 和 Task 都允许用户添加额外的自定义属性,要添加额外的属性,通过应用所属对应的 ext 属性即可实现。添加之后可以通过 ext 属性对自定义属性读取和设置,如果要同时添加多个自定义属性,可以通过 ext 代码块:
//自定义一个Project的属性
ext.age = 18
//通过代码块同时自定义多个属性
ext{
phone = 183207612
address = 'nanshan'
}
task hello << {
println "年龄是:${age}"
println "电话是:${phone}"
println "地址是:${address}"
}
在我们的项目中一般使用它来自定义版本号和版本名称,把版本号和版本名称单独放在一个 Gradle 文件中。因为它们每次发布版本都会改变,变动频繁,放到一个单独的 Gradle 文件中,便于管理,而且改动的时候也不会因为 Git 冲突影响整个 Buid 文件,便于解决冲突。
脚本即代码 代码也是脚本
虽然我们在一个 Gradle 文件中写脚本,但是我们写的都是代码,这一点一定要记清楚,这样你才能时刻使用 Groovy、Java以及 Gradle 的任何语法和 API 帮你完成你想做的事情。在这脚本文件上你可以定义 Class 内部类、导入包、定义方法、常量、接口、枚举等。
我们在项目中需要给生成的 APK 包以当前日期的格式命名,我们就定义了一个获取日期格式的方法,用于生成 APK 的文件名:
def buildTime(){
new Date().format('yyyyMMdd')
}
这只是使用的一个例子,目的是让大家灵活搭配 Java、 Groovy 和 Gradle,不要把它当成普通的脚本文件。