先来看一段代码,这是一个最简单常见的task
task hello{
doLast{
println'hello world!'
}
}
hello是什么?它也不是String,之前也没有任何地方定义过hello。为什么不会报错?
书上《Android gradle权威指南》其中3.4中对于gradle task的说法错误有些多。
(a)task是Project类的create方法。
首先Project类中没有叫做create的方法,task是Project类中task方法的。只有在TaskContainer中才有create方法。
(b)对于task taskName { closure}此类语法的错误理解。
其文中对task hello{closure }的表述为
若是了解Groovy的相关知识,咱们能够知道,若是最后一个参数是闭包的时候,能够放到括号外面,而后方法的括号能够省略,就生成了上面咱们的写法,很简洁。
//模拟的task方法
def task(arg,closure){
closure()
}
task "hello" {
println "hello world!"//抛异常 groovy.lang.MissingMethodException: No signature of method:
}
//正确的groovy语法如下所示
task "hello",{
println "hello world!"
}
task ("hello"){
println "hello world!"
}
那么为什么是task taskName { closure}这样的语法。这和我之前学的任何groovy语法都对不上。
实际上这是gradle AST(抽象语法树)的功劳。它类似于java中注解Processor对功能类似,实际上是编译时,gradle替我们做了刚刚的两件事情。
先来看hello怎么变成了"hello"?
源码在TaskDefinitionScriptTransformer类中,源码地址
主要代码
// 判断task后面的有几个表达式 如果是大于1个 例如 task hello {} 这种就有两个表达式匹配第一个if
// Matches: task <arg>{1, 3}
if (args.getExpressions().size() > 1) {
//用于判断是否有<name-value-pairs>,identifier就是taskname,这里就是将taskname的索引传入transformVariableExpression方法
//<name-value-pairs>暂时不管是什么东西
if (args.getExpression(0) instanceof MapExpression && args.getExpression(1) instanceof VariableExpression) {
// Matches: task <name-value-pairs>, <identifier>, <arg>?
// Map to: task(<name-value-pairs>, '<identifier>', <arg>?)
transformVariableExpression(call, 1);
} else if (args.getExpression(0) instanceof VariableExpression) {
// Matches: task <identifier>, <arg>?
transformVariableExpression(call, 0);
}
return;
}
// Matches: task <arg> or task(<arg>)
// 下面就是匹配task hello 或者 task("hello") 这里主要看第一种情况所以后续代码就不贴了
再看调用的方法transformVariableExpression
private void transformVariableExpression(MethodCallExpression call, int index) {
ArgumentListExpression args = (ArgumentListExpression) call.getArguments();
//获取到taskName的表达式
VariableExpression arg = (VariableExpression) args.getExpression(index);
if (!isDynamicVar(arg)) {
return;
}
// Matches: task args?, <identifier>, args? or task(args?, <identifier>, args?)
// Map to: task(args?, '<identifier>', args?)
//获取taskname的string值
String taskName = arg.getText();
//调用task方法
call.setMethod(new ConstantExpression("task"));
//将taskName的字符串替换掉原本的表达式,从而实现了hello->"hello"的转化
args.getExpressions().set(index, new ConstantExpression(taskName));
}
到这里你应该明白,实际上会将task hello {} 映射成task(‘hello’,{})。
有人会问是什么?看task的几个重载方法,其中有一个是
Task task(Map<String,?> args,
String name,
Closure configureClosure)
对应的args的解释就是
A map of creation options can be passed to this method to control how the task is created.
也就是用于创建task的一些option可选的属性值。至于有哪些属性,可以看后面的Task 属性的第三点 。