所有Gradle的构建工作都是由Tasks组合完成的。
1、多种方式创建任务
在gradle中,可以有多种方式创建任务。这依赖于Project给我们提供的快捷方法以及TaskContainer提供相关的Create方法。
1.1、直接以任务的名字创建任务
Task task(String name) throws InvalidUserDataException;
1.2、任务的名字 + 一个对该任务配置的Map对象的方式
Task task(Map<String, ?> args, String name) throws InvalidUserDataException;
示例:
def Task exeTask = task(group:BasePlugin.BUILD_GROUP,taskName)
Task参数中Map的可用配置
配置项 描述 默认值
type 基于一个存在的Task来创建,和继承差不多 DefaultTask
overwrite 是否替换存在的Task,和type配合起来用 false
dependsOn 任务依赖 []
action 添加到任务中的一个Action或者一个闭包 null
description 任务描述 null
group 任务分组 null
1.3、任务名字 + 闭包配置的方式
Task task(String name, Closure configureClosure);
Map的参数配置的方式可配置项有限,闭包的方式更加灵活,闭包里的委托对象就是Task,所以可以使用Task对象的任何方法、属性等信息。比如:
task defTask {
description "defTask"
doLast {
println "this is a defTask"
}
}
Base:查看Project中关于Task方法的源代码,可以发现其实它们最终都是调用TaskContainer对象中的create方法。
在Project中我们可以通过tasks属性访问TaskContainer。
2、多种方式访问任务
方式一:直接通过任务名访问任务
我们创建的任务都会作为Project的一个属性,属性名就是任务名,所以可以直接该任务名称访问和操纵该任务。
方式二:通过TaskContainer访问
任务都是通过TaskContainer创建的,其实TaskContainer就是我们创建的任务的集合,在Project中我们可以通过tasks属性访问TaskContainer,所以我们可以以访问集合的方式访问我们创建的任务。
tasks[‘excTask’].doLast{
}其中excTask就是任务名
知识扩展:[]在Groovy中是一个操作符,我们知道Groovy的具体操作符都有对应的方法让我们重载,a[b]对应的a.getAt(b),对应上面的例子tasks['excTask']其实调用的就是tasks.getAt('excTask'),查看Gradle的源码,发现最终都是通过findByName实现的。
方式三:tasks.findByName或者tasks.findByPath
3、任务分组及描述
def Task myTask = task customTask
myTask.group = BasePlugin.BUILD_GROUP
myTask.description = '这是一个构建的任务'
myTask.doLast {
println "任务描述:${myTask.description}"
}
-----------------
gradlew tasks
---------执行结果
.......
compileReleaseSources
compileReleaseUnitTestSources
customTask - 这是一个构建的任务
extractDebugAnnotations - Extracts Android annotations for the debug variant into the archive file
.......
分组和描述有助于快速方便的了解任务,也可以通过AS直接查看:
4、<<操作符(已过时,但可以了解一下)
<<操作符在Gradle的Task上等同于doLast
<<是操作符,在Groovy中是可以被重载的,a<<b对应的是a.leftShift(b),所以Task接口中一定有一个leftShift方法重载了<<操作符。
/**
* <p>Adds the given closure to the end of this task's action list. The closure is passed this task as a parameter
* when executed.</p>
*
* @param action The action closure to execute.
* @return This task.
*/
Task doLast(Closure action);
/**
* <p>Adds the given closure to the end of this task's action list. The closure is passed this task as a parameter
* when executed. You can call this method from your build script using the << left shift operator.</p>
*
* @param action The action closure to execute.
* @return This task.
*
* @deprecated Use {@link #doLast(Closure action)}
*/
@Deprecated
Task leftShift(Closure action);
从注释可以看出leftShift和doLast的作用都是将闭包放在了List的末尾
5、任务的执行分析
当执行一个任务的时候,其实就是执行其拥有的actions列表,这个列表保存在Task对象实例中的actions成员变量中,其类型就是一个List:
private List<ContextAwareTaskAction> actions;
@Override
public List<ContextAwareTaskAction> getTaskActions() {
if (actions == null) {
actions = new ArrayList<ContextAwareTaskAction>();
}
return actions;
}
doFirst、doLast其实就是将Action添加到列表的第一个、最后一个位置;
--------------------------------------
/**
* <p>Adds the given {@link Action} to the beginning of this task's action list.</p>
*
* @param actionName An arbitrary string that is used for logging.
* @param action The action to add
* @return the task object this method is applied to
*
* @since 4.2
*/
@Incubating
Task doFirst(String actionName, Action<? super Task> action);
/**
* <p>Adds the given {@link Action} to the end of this task's action list.</p>
*
* @param action The action to add.
* @return the task object this method is applied to
*/
Task doLast(Action<? super Task> action);
6、任务排序
// Specifies that this task should run after all of the supplied tasks.
task taskY {
shouldRunAfter "taskX"
}
// Specifies that this task must run after all of the supplied tasks.
task taskY {
mustRunAfter "taskX"
}
通过Task的上述两个方法可以在一定程度上定义一个任务与另一个任务的执行顺序。比如必须先执行单元测试然后再执行打包等
7、任务的启动和禁用
task defTask {
description "defTask"
doLast {
println "this is a defTask"
}
}
defTask.enabled = false
通过Task的enabled属性可以启用或禁用一个任务
8、任务的onlyIf断言
断言就是一个条件表达式。Task有一个onlyIf方法,接受一个闭包作为参数,如果该闭包返回true,则该任务执行。否则,跳过。借助这个特性,我们可以控制程序哪些情况下打什么包。什么时候执行单元测试,什么情况下执行单元测试的时候不执行网络测试。
task excA {
description "这是任务A"
doLast {
println "this is a excA"
}
}
task excB {
description "这是B任务 "
doLast {
println "this is a excB"
}
}
task excC {
description "这是任务C "
doLast {
println "this is a excC"
}
}
excC.dependsOn excA, excB
excA.onlyIf {
......
true
}
excB.onlyIf {
......//何种条件判断
false//最终结果
}
-----------------------执行结果-------------
> Task :excA
this is a excA
> Task :excC
this is a excC
从上述的执行结果可以看出,由于任务B返回了false,所以在执行任务C之前仅执行了任务A
9、任务规则
我们创建的任务都在TaskContainer里,是由其进行管理的,所以当我们访问任务的时候,都是通过TaskContainer进行访问的,而TaskContainer又是一个NamedDomainObjectCollection(继承它),所以定义任务的规则其实是NamedDomainObjectCollection的规则。
关系如下:
public interface TaskContainer extends TaskCollection<Task>, PolymorphicDomainObjectContainer<Task>
public interface TaskCollection<T extends Task> extends NamedDomainObjectSet<T>
public interface NamedDomainObjectSet<T> extends NamedDomainObjectCollection<T>, Set<T>
NamedDomainObjectCollection:
/**
* Adds a rule to this collection. The given rule is invoked when an unknown object is requested by name.
*
* @param rule The rule to add.
* @return The added rule.
*/
Rule addRule(Rule rule);
/**
* Adds a rule to this collection. The given closure is executed when an unknown object is requested by name. The
* requested name is passed to the closure as a parameter.
*
* @param description The description of the rule.
* @param ruleAction The closure to execute to apply the rule.
* @return The added rule.
*/
Rule addRule(String description, Closure ruleAction);
当我们执行一个不存在的任务的时候,Gradle会执行失败,失败信息是任务不存在。我们使用规则对其进行改进,当执行、依赖不存在的任务的时候,不会执行失败,而是打印提示信息。
tasks.addRule("对该规则的一个描述,便于调试和查看") { String taskName ->
task(taskName) {
doLast {
println "任务${taskName}不存在"
}
}
}
task excRuleTask {
dependsOn excTaskNone
}
执行结果:
> Task :excTaskNone
任务excTaskNone不存在