原文发于微信公众号 jzman-blog,欢送关注交换。
后面几篇学习了 Gradle 构建工作的基础知识,理解了 Project 和 Task 这两个概念,倡议先浏览后面几篇文章:
- Gradle 系列之初识 Gradle
- Gradle 之 Groovy 根底篇
- Gradle 系列之构建脚本根底
Gradle 的构建工作是有一系列的 Task 来实现的, 本文将针对 Task 进行具体介绍,本文次要内容如下:
- 多种形式创立工作
- 多种形式拜访工作
- 工作分组和形容
- 操作符
- 工作的执行剖析
- 工作排序
- 工作的启用和禁用
- 工作的 onlyIf 断言
- 工作规定
多种形式创立工作
Gradle 中能够应用多种形式来创立工作,多种创立工作的形式最终反映在 Project 提供的快捷办法以及内置的 TaskContainer 提供的 create 办法,上面是几种常见的创立工作的形式:
/**
* 第一种创立工作形式:* 办法原型:Task task(String name) throws InvalidUserDataException;
*/
// 定义 Task 变量接管 task()办法创立的 Task, 办法配置创立的 Task
def Task taskA = task(taskA)
// 配置创立的 Task
taskA.doFirst {println "第一种创立工作的形式"}
/**task
* 第二种创立工作形式:可在 Map 参数中进行相干配置,如依赖、工作形容、组别等
* 办法原型:Task task(Map<String, ?> args, String name) throws InvalidUserDataException;
*/
def Task taskB = task(group: BasePlugin.BUILD_GROUP,taskB,description: "形容")
// 配置创立的 Task
taskB.doLast {
println "第二种创立工作的形式"
println "工作 taskB 分组:${taskB.group}"
println "工作 taskB 形容:${taskB.description}"
}
/**
* 第三种创立工作形式:通过闭包的形式创立 Task, 闭包里的委托对象就是 Task, 即可在闭包内调用 Task
* 的所有属性和办法来进行 Task 的配置
* 办法原型:Task task(String name, Closure configureClosure);
*/
task taskC{
description 'taskC 的形容'
group BasePlugin.BUILD_GROUP
doFirst{
println "第三种创立工作的形式"
println "工作 taskC 分组:${group}"
println "工作 taskC 形容:${description}"
}
}
/**
* 第四种创立工作的形式:可在闭包中灵便配置,也可在 Map 参数中配置,闭包中中的配置父笼罩 Map 中雷同的配置
* 办法原型:Task task(Map<String, ?> args, String name, Closure configureClosure);
*/
def Task taskD = task(group: BasePlugin.BUILD_GROUP,taskD,description: "形容"){
description 'taskD 的形容'
group BasePlugin.UPLOAD_GROUP
doFirst{
println "第四种创立工作的形式"
println "工作 taskD 分组:${group}"
println "工作 taskD 形容:${description}"
}
}
下面是创立工作的四种形式,应用时抉择适合的创立形式即可,下面提到 Map 中能够配置 Task 的相干参数,上面是是 Map 中可应用的配置:
type:基于一个已存在的 Task 来创立,相似于类的继承,默认值 DefaultTask
overwrite:是否替换存在的 Task, 个别和 type 配合应用,默认值 false
dependsOn:配置当前任务的依赖,默认值[]
action:增加到工作中的一个 Action 或者是一个闭包,默认值为 null
description:工作形容,默认值 null
group:工作分组,默认值 null
通过闭包的形式创立 Task, 闭包里的委托对象就是 Task,即可在闭包内调用 Task
的所有属性和办法来进行 Task 的配置,能够说应用闭包的这种工作创立形式更灵便,此外还能够应用 TaskContainer 创立工作,参考如下:
// 应用 TaskContainer 创立工作的形式
tasks.create("taskE"){
description 'taskE 的形容'
group BasePlugin.BUILD_GROUP
doFirst{
println "第三种创立工作的形式"
println "工作 taskE 分组:${group}"
println "工作 taskE 形容:${description}"
}
}
tasks 是 Project 的属性,其类型是 TaskContainer,所以能够通过 tasks 来创立工作,当然 TaskContainer 创立工作也有创立工作的其余构造方法,到此对于工作的创立就根本介绍完了。
多种形式拜访工作
创立的工作 (Task) 属于我的项目 (Project) 的一个属性,其属性名就是工作名,该属性的类型是 Task,如果已知工作名称,那么能够通过工作名间接拜访和操纵该工作了,也能够了解拜访和操纵该工作所对应的 Task 对象,参考
如下:
/**
* 拜访工作的第一种形式:Task 名称.doLast{}
*/
task taskF{
}
taskF.doLast{println "第一种拜访工作的形式"}
工作都是通过 TaskContainer 的 create 办法创立的,而 TaskContainer 是创立工作的汇合,在 Project 中可通过 tasks 属性拜访 TaskContainer ,tasks 的类型就是 TaskContainer,所以对于曾经创立的工作可通过拜访几何元素的形式拜访已创立工作的属性和办法,参考代码如下:
/**
* 拜访工作的第二种形式:应用 TaskContainer 拜访工作
*/
task taskG{
}
tasks['taskG'].doLast {println "第二种拜访工作的形式"}
在 Groovy 中 [] 也是一个操作符,下面 tasks[‘taskG’] 的真正含意是 tasks.getAt(‘taskG’) , getAt() 办法在 TaskCollection 中的办法,这样能够通过工作名称对相干工作进行拜访和操作。
还能够通过门路拜访的形式拜访工作,通过门路拜访工作有两个要害办法:findByPath 和 getByPath,区别在于前者找不到指定工作的时候会返回 null,后者找不到工作的时候会抛出 UnknowTaskException 异样,代码参考如下:
/**
* 拜访工作的第三种形式:应用门路拜访工作
*/
task taskH{
println 'taskH'
// 通过门路拜访工作,参数能够是门路(没有拜访胜利,写法如下)println tasks.findByPath(':GradleTask:taskG')
// 通过门路拜访工作,参数能够是工作名称
println tasks.findByPath('taskG')
println tasks.getByPath('taskG')
}
上述代码执行后果参考如下:
PS E:\Gradle\study\GradleTask> gradle taskH
> Configure project :
taskH
null
task ':taskG'
task ':taskG'
FAILURE: Build failed with an exception.
* Where:
Build file 'E:\Gradle\study\GradleTask\build.gradle' line: 98
* What went wrong:
A problem occurred evaluating root project 'GradleTask'.
> Task with path 'test' not found in root project 'GradleTask'.
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
* Get more help at https://help.gradle.org
BUILD FAILED in 2s
应用门路拜访工作的过程,参数写成门路拜访不到具体的工作,可能是写法问题,心愿在前面的学习中可能解决。
此外,还能够通过工作名称拜访,办法次要是 findByName 和 getByName,区别和第三种拜访形式一样,代码参考如下:
/**
* 拜访工作的第四种形式:应用工作名称拜访
*/
task taskJ
tasks['taskJ'].doLast{
println 'taskJ'
println tasks.findByName('taskJ')
println tasks.getByName('taskJ')
}
下面学习了拜访工作的四种形式,通过对 Gradle 拜访工作的理解,在具体的我的项目构建上在联合下面拜访工作的形式灵便应用。
工作分组和形容
对于工作分组及形容实际上在之前的文章曾经提到过且配置过,这里再简略阐明一下,工作分组和形容实际上就是对曾经创立的工作配置分组和工作形容,如上面这样配置:
// 工作分组与形容
def Task task1 = task taskK
task1.group = BasePlugin.BUILD_GROUP
task1.description = '测试工作分组与形容'
task1.doLast {println "taskK is group = ${group}, description = ${description}"
}
上面是上述代码执行后果,参考如下:
PS E:\Gradle\study\GradleTask> gradle taskK
> Task :taskK
taskK is group = build, description = 测试工作分组与形容
BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
从执行后果能够看出,如果配置了工作的相干属性,那么就能够拜访到工作的所有信息了。
操作符
学习一个操作符 <<,之前的测试代码中为了测试都会调用 task.doLast() 办法,咱们能够应用 << 操作符来代替 doLast 办法,也就是说 daLast() 办法能够这样写:
//<< 工作操作符
// 简写形式,Gradle 5.0 开始以不举荐这种写法
task taskL <<{println "doLast"}
// 举荐写法
task taskL{
doLast{println "doLast"}
}
上述两种写法的执行后果参考如下:
PS E:\Gradle\study\GradleTask> gradle taskL
> Configure project :
The Task.leftShift(Closure) method has been deprecated and is scheduled to be removed in Gradle 5.0. Please use Task.doLast(Action) instead.
at build_6syzx8ks0l09hby4j6yn247u9.run(E:\Gradle\study\GradleTask\build.gradle:123)
> Task :taskL
doLast
BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
PS E:\Gradle\study\GradleTask> gradle taskL
> Task :taskL
doLast
BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
PS E:\Gradle\study\GradleTask>
从输入后果能够看到两种写法都输入了想要的后果,同时察看日志发现这种简写形式曾经在 Gradle 5.0 开始曾经被放弃,所以举荐搭建应用 doLast 的形式配置工作。
工作的执行剖析
在 Gradle 工作执行过程中,咱们能够通过 doFirst 和 doLast 在工作执行之前或执行之后进行工作相干配置, 当咱们执行一个工作的时候,实际上是在执行该 Task 所领有的 action,能够通过 getActions() 办法获取所有能够执行的 action,上面自定义一个 Task 类型 CustomTask,并应用注解 @TaskAction 标注办法 doSelf 示意 Task 自身要执行的办法,代码如下:
// 工作执行流程剖析
def Task taskA = task taskB(type: CustomTask)
taskA.doFirst {println "Task 执行之前调用:doFirst"}
taskA.doLast {println "Task 执行之后调用:doLast"}
class CustomTask extends DefaultTask{
@TaskAction
def doSelf(){println "Task 执行自身调用:doSelf"}
}
上述代码的执行后果如下:
PS E:\Gradle\study\GradleTask2> gradle taskB
> Task :taskB
Task 执行之前调用:doFirst
Task 执行自身调用:doSelf
Task 执行之后调用:doLast
BUILD SUCCESSFUL in 2s
1 actionable task: 1 executed
因为 Task 的执行是在遍历须要执行的 action 列表,为了保障执行的程序,则必须将 doFirst 对应的 action 放在 action 列表的最后面,doLast 对应的 action 放在 action 列表的最初面,doSelf 对应的 action 搁置在列表的两头地位,这样就能保障对应的执行程序了,上面是伪代码:
// 创立工作的时候将应用 @TaskAction 标注的办法作为 Task 自身执行的 Task
// 此时, 工作正在创立,actionList 外面只有 Task 自身执行的 Action
actionList.add(0,doSelfAction)
// 工作创立实现之后,如果设置了 doFirst 则会在 actionList 最后面增加 doFist 对应的 action
// 此时,doFirst 对应的 action 增加 actionList 的最后面,保障了 doFirst 办法在工作开始执行之前执行
actionList.add(0,doFirstAction)
// 工作创立实现之后,如果设置了 doLast 则会在 actionList 最初面增加 doLast 对应的 action, 保障了 doLast 办法在工作开始执行之后执行
actionList.add(doLastAction)
工作执行的流程根本如上,尽量在具体实际中多领会。
工作排序
Gradle 中工作排序应用到的是 Task 的两个办法 shoundRunAfter 和 mustRunAfter,能够不便的管制两个工作谁先执行:
/**
* 工作程序
* taskC.shouldRunAfter(taskD):示意 taskC 要在 taskD 的前面执行
* taskC.mustRunAfter(taskD):示意 taskC 必须要在 taskD 的前面执行
*/
task taskC {
doFirst{println "taskC"}
}
task taskD {
doFirst{println "taskD"}
}
taskC.shouldRunAfter(taskD)
上述代码的执行后果,参考如下:
PS E:\Gradle\study\GradleTask2> gradle taskC taskD
> Task :taskD
taskD
> Task :taskC
taskC
BUILD SUCCESSFUL in 2s
2 actionable tasks: 2 executed
工作的启用和禁用
Task 中有个 enabled 属性,能够应用该属性启用和禁用某个工作,设置为 true 则启用该工作,反之则禁用该工作,该属性默认为 true,应用如下所示:
taskA.enabled = true
工作的 onlyIf 断言
断言是一个条件表达式,Task 对象有一个 onlyIf 办法,该办法能够接管一个闭包作为参数,如果该闭包内参数返回 true,则该工作执行,反之则不执行该工作,这样能够通过工作的断言来管制那些工作须要执行,上面通过一个打包的案列来学习工作的断言,代码参考如下:
// 工作的 onlyIf 断言
final String BUILD_ALL = 'all'
final String BUILD_FIRST = 'first'
final String BUILD_OTHERS = 'others'
task taskTencentRelease{
doLast{println "打利用宝渠道包"}
}
task taskBaiduRelease{
doLast{println "打百度手机助手渠道包"}
}
task taskMiuiRelease{
doLast{println "打小米利用商店渠道包"}
}
task buildTask{
group BasePlugin.BUILD_GROUP
description "打渠道包"
}
// 为 buildTask 增加依赖的具体任务
buildTask.dependsOn taskTencentRelease, taskBaiduRelease, taskMiuiRelease
taskTencentRelease.onlyIf{if (project.hasProperty("buildApp")){Object buildApp = project.property("buildApp")
return BUILD_ALL == buildApp || BUILD_FIRST == buildApp
}else{return true}
}
taskBaiduRelease.onlyIf{if (project.hasProperty("buildApp")){Object buildApp = project.property("buildApp")
return BUILD_ALL == buildApp || BUILD_FIRST == buildApp
}else{return true}
}
taskMiuiRelease.onlyIf{if (project.hasProperty("buildApp")){Object buildApp = project.property("buildApp")
return BUILD_OTHERS == buildApp || BUILD_ALL == buildApp
}else{return true}
}
上面是上述代码的执行后果:
PS E:\Gradle\study\GradleTask2> gradle -PbuildApp=first buildTask
> Task :taskBaiduRelease
打百度手机助手渠道包
> Task :taskTencentRelease
打利用宝渠道包
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
PS E:\Gradle\study\GradleTask2> gradle -PbuildApp=others buildTask
> Task :taskMiuiRelease
打小米利用商店渠道包
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
PS E:\Gradle\study\GradleTask2> gradle -PbuildApp=all buildTask
> Task :taskBaiduRelease
打百度手机助手渠道包
> Task :taskMiuiRelease
打小米利用商店渠道包
> Task :taskTencentRelease
打利用宝渠道包
BUILD SUCCESSFUL in 1s
3 actionable tasks: 3 executed
能够看出,当咱们执行 buildTask 时为 Project 配置了属性 buildApp,通过 buildApp 不同的值,借助 onlyIf 实现了不同渠道包的定制打包策略,可在理论开发中借鉴加以应用。
此外,留神上述代码执行命令的写法,具体如下:
// 其中 buildApp 和 = 前面的值 others 是键值对的关系,应用命令执行工作时可应用 - P 命令简写
//- P 要为以后 Project 指定 K - V 的属性键值对,即 -PK=V
gradle -PbuildApp=others buildTask
工作规定
创立的工作都是在 TaskContain 外面,我么能够通过从 Project 的属性 tasks 中依据工作的名称来获取想要获取的工作,能够通过 TaskContain 的 addRule 办法增加相应的工作规定,参考代码如下:
// 工作规定
tasks.addRule("对该规定的一个形容"){
// 在闭包中经常将 -> 作为参数与代码块之间的分隔符
String taskName ->
task(taskName) {
doLast{println "${taskName} 不存在"
}
}
}
task taskTest{dependsOn taskX}
上述代码的执行后果:
PS E:\Gradle\study\GradleTask2> gradle taskTest
> Task :taskX
taskX 不存在
BUILD SUCCESSFUL in 1s
1 actionable task: 1 executed
如果不指定对某些非凡状况的工作解决,则会报错,如果解决了则会输入相干的提示信息,Gradle 工作的理解和学习就到此为止。能够关注公众号:躬行之(jzman-blog),一起交流学习。