Gradle理论与实践三:Gradle构建脚本基础
Gradle系列相关文章:
1、Gradle理论与实践一:Gradle入门
2、Gradle理论与实践二:Groovy介绍
3、Gradle理论与实践三:Gradle构建脚本基础
4、Gradle理论与实践四:自定义Gradle插件
5、Gradle配置subprojects和allprojects的区别:subprojects和allprojects的区别
Gradle构建脚本基础
-
Project:根据业务抽取出来的一个个独立的模块
-
Task:一个操作,一个原子性操作。比如上传一个jar到maven中心库等
-
Setting.gradle文件:初始化及整个工程的配置入口
-
build.gradle文件:
每个Project都会有个build.gradle的文件,是Project构建的入口。Root Project也有一个build.gradle文件,可以获取到所有的Child Project,并且可以对所有的Child Project进行统一配置:如应用的三方插件、三方依赖库等。如,我们可以在Root Project的build.gradle文件里配置:
allprojects {
repositories {
jcenter()
}
}
这样项目中所有依赖的三方库都可以在jcenter中下载了,省去了对每个Project去配置的情况。
上面用到的是allprojects,还可以配置subprojects,他们的区别在于:allprojects是对所有project的配置,包括Root Project。而subprojects是对所有Child Project的配置。更详细的请移步:https://blog.csdn.net/u013700502/article/details/85231687
1、创建一个task
Task的创建方式,可以是:
task hello {
doFirst {
print 'hello:doFirst\n'
}
doLast {
print 'hello:doLast\n'
}
}
也可以是:
tasks.create("hello") {
doFirst {
print 'hello:doFirst'
}
doLast {
print 'hello:doLast'
}
}
他们执行的结果都是一样的:
bogon:test_gradle mq$ gradle -q hello
hello:doFirst
hello:doLast
task是Project对象的一个函数,原型为Task create(String name, Closure configureClosure),最后一个参数是闭包的时候,可以放到括号外面,并且括号可以省略,task中的doFirst和doLast分别在任务前后执行。
2、创建Task的几种方式
- 1、调用Project对象的task(String name)方法,如:
def Task hello = task(hello);
hello << {
print 'hello\n'
}
输出:
bogon:test_gradle mq$ gradle -q hello
hello
- 2、任务名字+闭包方式,如:
task hello {
description '任务描述'
doLast {
print "方法原型: Task task(String name, Closure configureClosure)\n"
print "任务描述: ${description}"
}
}
输出结果:
bogon:test_gradle mq$ gradle -q hello
方法原型: Task task(String name, Closure configureClosure)
任务描述: 任务描述
- 3、TaskContainer方式创建:
tasks.create('hello') {
description '任务描述'
doLast {
print "方法原型: Task create(String name, Closure configureClosure)\n"
print "任务描述: ${description}"
}
}
输出结果:
方法原型: Task create(String name, Closure configureClosure)
任务描述: 任务描述
tasks是Project的属性,其类型是TaskContainer。其中1和2的创建最终也是调用TaskContainer方式创建的。
3、Task内部执行顺序
当我们执行Task的时候,就是执行其拥有的actions列表,是一个List。把Task执行之前、Task本身执行、Task之后执行分别称为doFirst、doSelf、doLast,先来看个例子:
def Task hello = task myTask(type: CustomTask);
hello.doFirst {
print 'Task执行之前 do-First\n'
}
hello.doLast {
print 'Task执行之后 do-Last\n'
}
class CustomTask extends DefaultTask {
@TaskAction
def doself() {
print 'Task执行自身 do-self\n'
}
}
输出:
bogon:test_gradle mq$ gradle -q hello
Task执行之前 do-First
Task执行自身 do-self
Task执行之后 do-Last
通过结果发现确实是按照我们想要的顺序执行的。Gradle在执行hello这个任务的时候,Gradle会解析其带有@TaskAction注解的方法作为其Task执行的Action,并且把其加入到actionList中。而doFirst、doLast分别会在actionList的最前面和最后面加入,所以之后就达到了按顺序执行。
4、Task任务依赖
任务之间是可以有依赖关系的,使用dependsOn执行当前task依赖的任务,如:
task hello << {
print 'hello '
}
task world(dependsOn: hello) {
doLast {
print 'world'
}
}
此时执行gradle -q world
,结果如下:
bogon:test_gradle mq$ gradle -q world
hello world
因为world任务是依赖hello的,所以当执行world后,先去执行了hello任务,再执行world任务。dependsOn是Task类的一个方法,可以接受多个依赖的任务作为参数。
修改以下程序:
task hello << {
print 'hello\n'
}
task world(dependsOn: hello) {
doLast {
print 'world\n'
}
}
world.doFirst {
print 'doFirst\n'
}
world.doLast {
print 'doLast2\n'
}
结果:
bogon:test_gradle mq$ gradle -q world
hello
doFirst
world
doLast2
通过结果可以看出,doFirst和doLast可以使用多次,并且按顺序执行。doLast可以用 << 操作符替代。
5、自定义属性
Project和Task允许添加额外自定义属性,通过对应的ext属性即可,如
//自定义一个Project的属性
ext.buildTime = '2018'
//自定义多个属性
ext {
buildTime = '2018'
month = '12'
}
task time {
doLast {
print "构建时间${buildTime} 年${month}月 \n"
}
}
执行gradle -q time
,执行结果:
bogon:test_gradle mq$ gradle -q time
构建时间2018 年12月
可见我们自定义的属性正确地取到了,自定义属性的作用域很广,只要能得到对应的Project,就能获取到定义的属性值。在Android中我们通常使用自定义属性值来定义我们的版本号、版本名称等,把这些放到一个单独的gradle文件中,因为他们在发版前就会变动,放到单独的gradle文件中便于管理,在AS根目录下新建config.gradle如下:
//config.gradle
ext {
android = [
compileSdkVersion: 26,
buildToolsVersion: "25.0.0",
versionName : "6.2.1",
versionCode : 6210,
minSdkVersion : 16,
targetSdkVersion : 23
]
}
在APP对应的build.gradle中取值:
//build.gradle
apply from: rootProject.getRootDir().getAbsolutePath() + '/config.gradle'
compileSdkVersion rootProject.ext.android.compileSdkVersion
buildToolsVersion rootProject.ext.android.buildToolsVersion
就可以获取到自定义的属性值。
上例中,除了能获取到config.gradle中的属性值,还可以在builg.gradle中调用config.gradle中的方法,具体实现:
//config.gradle
ext {
.......其他.........
//注意方法和属性写法的区别
copyApk = this.©Apk
}
def copyApk() {
}
在build.gradle调用:
//build.gradle
apply from: rootProject.getRootDir().getAbsolutePath() + '/config.gradle'
copyApk()
这样就实现了在build.gradle中调用config.gradle中的copyApk()方法了。