Gradle构建脚本基础

<<Android Gradle权威指南》阅读笔记——Groovy基础

​ 本文讲述Gradle构建脚本基础,一步步了解什么是Settings文件?什么是Build文件?什么是Project?什么是Task?什么是自定义属性?


[TOC]

1. Settings文件

Groovy中,单引号和双引号都可以定义一个字符串常量(Java里单引号定义一个字符),不同的是单引号标记的是纯粹的字符串常量,而不是对字符串里表达式做运算,单引号没有运算能力,双引号可以:

  • 类型:

    1
    2
    3
    4
    5
    6
    7
    task printStringClass << {
    def str1 = '单引号'
    def str2 = "双引号"

    println "单引号定义的字符串类型:"+str1.getClass().name
    println "双引号定义的字符串类型:"+str2.getClass().name
    }

    ./gradlew printStringClass 输出

    1
    2
    3
    > Task :printStringClass
    单引号定义的字符串类型:java.lang.String
    双引号定义的字符串类型:java.lang.String
  • 运算

    1
    2
    3
    4
    5
    6
    task printStringVar << {
    def name = "张三"

    println '单引号的变量计算:${name}'
    println "双引号的变量计算:${name}"
    }

    ./gradlew printStringVar 输出

    1
    2
    3
    > Task :printStringVar
    单引号的变量计算:${name}
    双引号的变量计算:张三

2. 集合

Groovy完全兼容了Java的集合,并进行了扩展,使操作变得更容易。

  • List

    Grroovy中实现List非常简单,同时还提供了下标索引负下标范围索引迭代操作(each)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    task printList << {
    def numList = [1,2,3,4,5,6];
    println numList.getClass().name //输出时可以看出 numList 是一个 ArrayList

    println numList[1]//访问第二个元素 下标索引 下标从 0 开始
    println numList[-1]//访问最后一个元素 负下标
    println numList[-2]//访问倒数第二个元素 负下标
    println numList[1..3]//访问第二个到第四个元素 范围索引 由”.."分开

    numList.each{//迭代操作
    println it //it 正在迭代的元素,这里涉及闭包的知识,下文会讲解
    }
    }

    ./gradlew printList 输出

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    > Task :printList
    java.util.ArrayList
    2
    6
    5
    [2, 3, 4]
    1
    2
    3
    4
    5
    6

  • Map

    Map的用法和List类似,区别在于它的值是K:V`键值对

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    task printMap << {
    def mapl = ['width':1920,'height':1080]
    println mapl.getClass().name //输出可以看出mapl是一个LinkedHashMap

    //访问可以采用map[key]或者map.key两种方式
    println mapl['width']
    println mapl.height

    mapl.each{//迭代操作
    println "Key:${it.key},Value:${it.value}"//此处的it是一个Map.Entry实例
    }
    }

    ./gradlew printMap 输出

    1
    2
    3
    4
    5
    6
    > Task :printMap
    java.util.LinkedHashMap
    1920
    1080
    Key:width,Value:1920
    Key:height,Value:1080

关于集合的更多方法后续会补充,有兴趣的可以自行先了解

3. 方法

通过了解Groovy方法和Java方法的不同,更利于我们明白Gradle脚本里的代码

  • 括号可以省略

    Groovy调用一个方法比Java灵活的多,可以省略(),在定义DSL时非常有用并且书写方便

    1
    2
    3
    4
    5
    6
    7
    8
    9
    task invokeMethod << {
    //这两种调用方式结果一直,但第二种更简洁
    methodl (1,2)
    methodl 1,2
    }

    def methodl(int a, int b){
    println a+b
    }

    ./gradlew invokeMethod 输出

    1
    2
    3
    > Task :invokeMethod
    3
    3
  • return 可以不写

    Groovy在没有return时,会将方法执行过程中的最后一句作为返回值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    task printMethodReturn << {
    def add1 = method2 1,2
    def add2 = method2 5,3
    println "add1:${add1},add2:${add2}"
    }

    def method2(int a,int b){
    if(a>b){
    a //执行到此处 返回a
    }else{
    b //执行到此处 返回b
    }
    }

    ./gradlew printMethodReturn 输出

    1
    2
    > Task :printMethodReturn
    add1:2,add2:5
  • 代码块可以作为参数传递

    通过each方法,我们可以直接的理解这个问题

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    //最初的写法
    numList.each({println it})

    //经过格式化
    numList.each({
    println it
    })

    //Groovy中方法的最后一个参数为闭包,可以放到外面
    numList.each(){
    println it
    }

    //去掉方法的括号
    numList.each{
    println it
    }

4. JavaBean

JavaBean中繁琐的getter/setterGroovy中得到了很大改善

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
task helloJavaBean << {
Person p = new Person()

println "名字是:${p.name}"//此时name为赋值,返回null
p.name = 'tom'
println "名字是:${p.name}"//已赋值,返回tom
println "年龄是:${p.age}"//未定义成员变量时,通过getAge()方法也可获取age,但不能修改值
}

class Person{
private String name
public int getAge(){
12
}
}

./gradlew helloJavaBean 输出

1
2
3
4
> Task :helloJavaBean
名字是:null
名字是:tom
年龄是:12

5. 闭包

闭包是Groovy的一个非常重要的特性,可以说他是DSL的基础。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
task helloClosure << {
//使用自定义闭包
customEach {
println it
}


//多个参数
eachMap {k,v ->
println "${k} is ${v}"
}
}

def customEach(closure){//唯一参数,用于接收一个闭包(代码块)
//模拟一个集合,开始迭代
def numList = [1,2,3]
numList.each{
closure(it)
}
}

def eachMap(closure){//此处的闭包传递两个参数k v
def mapl = ["name":"tom","age":18]
mapl.each{
closure(it.key,it.value)
}
}

./gradlew helloClosure 输出

1
2
3
4
5
6
> Task :helloClosure
1
2
3
name is tom
age is 18
  • 闭包委托

Groovy闭包的强大之处在于它支持闭包方法的委托。Groovy的闭包有thisObject,owner,delegate三个属性,当你在闭包内调用方法时,由它们来确定使用哪个对象来处理。默认情况下delegateowner是相等的,但是delegate是可以被修改的,这个功能是非常强大的,Gradle中的很多功能都是通过修改delegate实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
task helloDelegate << {
new Delegate().test{
println "thisObject:${thisObject.getClass()}" //thisObject优先级最高
println "owner:${owner.getClass()}"//owner优先级次之
println "delegate:${delegate.getClass()}"
//delegate优先级最低,但是owner==delegate
//闭包内方法的执行顺序:thisObject>owner>delegate
method3()
it.method3()
}
}

def method3(){
println "Context this:${this.getClass()} in root"
println "method3 in Delegate"
}

class Delegate{
def method3(){
println "Delegate this:${this.getClass()} in Delegate"
println "method3 in Delegate"
}

def test(Closure<Delegate> closure){
closure(this)
}
}

./gradlew helloDelegate 输出

1
2
3
4
5
6
7
8
> Task :helloDelegate
thisObject:class build_edqlj0scrowqqm8jgfgirxcz4
owner:class build_edqlj0scrowqqm8jgfgirxcz4$_run_closure10
delegate:class build_edqlj0scrowqqm8jgfgirxcz4$_run_closure10
Context this:class build_edqlj0scrowqqm8jgfgirxcz4 in root
method3 in Delegate
Delegate this:class Delegate in Delegate
method3 in Delegate

DSL中,比如Gradle,我们会指定delegate为当前的it,这样我们在闭包内就可以对该it进行配置,或调用其方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
task configClosures << {
man {//在闭包类直接对Man实例配置
manName = "tom"
manAge = 19
dumpMan()
}
}

class Man{
String manName
int manAge

def dumpMan(){
println "name is ${manName},age is ${manAge}"
}
}

def man(Closure<Person> closure){
Man p = new Man();
//设置委托对象为当前创建的Man实例
closure.delegate = p
//委托模式优先
closure.setResolveStrategy(Closure.DELEGATE_FIRST);
closure(p)
}

./gradlew configClosures 输出

1
2
> Task :configClosures
name is tom,age is 19

6. DSL

DSL(Domain Specific Language)——领域特定语言(专门关注某一领域的语言)

Gradle就是一门DSL,它基于Groovy专门解决自动化构建的DSL

到这Groovy基础就简单介绍完了,后续我们再学习新的Gradle知识,欢迎持续关注

您的支持将鼓励我继续创作!