本节我们从整体的角度来介绍一下Gradle。
一、setting.gradle
在Gradle中,定义了一个设置文件,用于初始化以及工程树的配置。设置文件的默认的名字就是setting.gradle,此文件位于根工程目录下。
setting.gradle 的作用就是为了配置子工程。在Gradle中,多工程是通过工程树表示的,相当于我们在Android Studio下面看到的Project和Module概念一样。根工程相当于Android Studio的Project,一个根工程可以有多个子工程,也就是很多的Module,这样就和Android Studio定义的Module概念对应上了。
一个子工程(Module)只有在Setting文件里配置了Gradle才会识别,才会在构建的时候被包含进去。
二、build.gradle
每个Project都会有一个build.gradle文件,该文件是该Project构建的入口,可以在这里针对该Project进行配置,比如配置版本,需要哪些插件,依赖哪些库等等。
既然每个Project都会有一个build.gradle,那么Root Project可以获取到所有的Child Project,所以在Root Project的Build文件里面,我们可以对Child Project进行统一的配置,比如应用的插件,依赖的Maven中心库等等。
例如,我们经常能在Root目录下的build.gradle文件中看到如下配置:
...
allprojects {
repositories {
google()
jcenter()
}
}
...
这样配置会非常方便,省去了我们对每个Project都去配置的情况,特别是对于要管理很多的Project的大工程来说。
三、Project 及 Tasks 介绍
在Gradle中,可以有很多Project,你可以定义创建一个Project用于生成一个jar,也可以定义一个另外一个Project用于生成一个war包,还可以定义一个Project用于发布上传你的war等等。其实在Gradle里面,你可以将Poject理解为在你的业务范围内,抽象出来的一个个独立的模块,你可以根据项目的情况抽象归类,最后这一个个的Project组成了你的整个Gradle构建。从我们编程的角度来讲,它们就是一个个独立的模块。好好利用他们,这样你的代码就能够做到低耦合,高内聚。
一个Project里面由包含多个Task,也就是每个Project是由多个Task组成的。那么什么是Task呢?这里我们可以去一个项目的RootProject里面的build.gradle查看,最常见的task如下:
task clean(type: Delete) {
delete rootProject.buildDir
}
具体的含义相信大家都能理解,这里就不过多赘述了。
Task 是一个操作,一个原子性的操作,比如打个jar包,复制一份文件,编译一次Java代码,上传一个jar到Maven中心库等,这就是一个Task。
四、Task 详解
1. 创建一个任务(Task)
创建一个任务很简单,前面很多例子我们也都有演示:
task customTask1 {
doLast {
println 'customTask1:doLast'
}
doFirst {
println 'customTask1:doFirst'
}
}
输出结果如下:
> Task :customTask1
customTask1:doFirst
customTask1:doLast
这里的Task看着像一个关键字,其实它是Project对象的一个函数,原型为create(String name,Closure configureClosure)。customTask1为任务的名字,我们可以自定义,第二个参数是一个闭包,也就是我们花括号里面的代码块。
如果了解Groovy的相关知识,我们可以知道,如果最后一个参数是闭包的时候,可以放到括号外面,然后方法的括号可以省略,就生成了上面我们的写法,很简洁。该闭包的作用就是用来对我们创建的任务进行配置,例子中我们用了任务的doFirst和doLast方法,分别在任务执行前后输出一段文字。上面的任务我们还可以改为如下的方式来定义,作用是一样的:
tasks.create("customTask1") {
doLast {
println 'customTask1:doLast'
}
doFirst {
println 'customTask1:doFirst'
}
}
除此之外,Task还有其他方法和属性可以使用,需要我们参考Gradle Task的API进一步学习。
2. 任务依赖
Task之间是可以有依赖关系的,这样我们就可以控制哪些任务先于哪些任务执行;哪些任务执行后,其他任务才能执行。比如,我们运行jar任务之前,compile任务一定要执行过,也就是jar依赖compile。Android 的install任务一定要依赖package任务进行打包生成APK,才能安装进设备里面。
下面我们来举一个非常简单的例子,说明一下:
task outHello {
println 'hello'
}
task outMain(dependsOn: outHello) {
doLast {
println 'main'
}
}
输出如下:
renhui:android-gradle-book-code renhui$ gradle outMain
> Configure project :
hello
> Task :outMain
main
从例子中,我们可以看出,在创建任务的时候,通过dependsOn可以指定其依赖的任务。
五、自定义属性
Project 和 Task 都允许用户添加额外的自定义属性,要添加额外的自定义属性,可以使用应用所属的对应的ext即可实现。添加之后可以通过ext属性对自定义属性读取和设置,如果要同时添加多个自定义属性,可以通过ext代码块:
ext.age = 18
ext {
phone = 123455
address = '保定'
}
task outMain() {
println "年龄是:${age}"
println "电话是:${phone}"
println "年龄是:${address}"
}
输出结果为:
> Configure project :
年龄是:18
电话是:123455
年龄是:保定
相比局部变量,自定义属性有更加广泛的作用域,你可以跨Project,跨Task访问这些自定义属性。只要你能访问这些属性所属的对象,你就能访问到这些属性。
自定义属性不仅仅局限在Task和Project上,你可以应用在SourceSet中,这样等于每种SourceSet多了一个可供配置的属性。而我们在Android开发中,就经常会用到main SourceSet,当使用productFlavors定义多个渠道的时候,还会新增其他很多的sourceSet。这块的相关内容,可以在以后的开发过程中多留意和学习使用。