Gradle自学——构建脚本

292 阅读4分钟

Gradle自学——构建脚本

1. 认识构建脚本

Gradle所做的事情往往是由一个个任务组成的,而每一个任务可以认为是一个原子操作

通过gradle命令可以运行Gradle构建,这个命令会去当前目录下寻找build.gradle文件,而这个文件被称为构建脚本

当然,在使用命令之前还是需要事先配置一下GRADLE_HOME的环境变量

接下来,开始编写第一个构建脚本,可以直接在Android项目的目录下的build.gradle文件中进行编写

tasks.register('hello') {
    doLast {    // 这就是Action
        println 'Hello World'
    }
}

然后回到当前目录下,输入命令gradle -q hello,这个命令是什么意思?直接gradle -h查看帮助文档

image.png 这个参数的含义是只输出报错日志,过滤了其他日志,因此只会显示结果 image.png 以上内容仅仅是定义了一个task,并且向其中添加了一个Action,作为任务执行的具体逻辑 image.png 查阅DSL的手册,可以找到关于doLast这个Action的定义,这将会在当前Task中作为最后执行的Action

2. Task依赖

一个Task是可以依赖于其他Task

tasks.register('hello') {
    doLast {
        println 'Hello World'
    }
}

tasks.register('something') {
    dependsOn tasks.hello   // 依赖于另一个任务
    doLast {
        println '还有一件事'
    }
}

既然something任务需要依赖于hello任务,那么hello就会先执行,然后轮到something,当然,这与你定义的位置无关

image.png

3. Task注册

可以非常方便地对于任务进行批量注册

10.times { i ->      // 0-9,注册10个任务
    tasks.register("task$i") {
        doLast {
            println "task $i done"
        }
    }
}

既然都注册了,直接挑一个执行一下

$ gradle -q task9
task 9 done

4. 操作已经存在的Task

这些任务完成注册之后,其实就存在于当前项目下的任务列表中,我们可以对其进行一些操作

tasks.named('task3') {
    dependsOn ('task7', 'task8')
}

执行3的前提是7和8执行完毕

$ gradle -q task3
task 7 done
task 8 done
task 3 done

接下来,再利用doFirstdoLast组合对同一个已注册的Task进行操作 image.png image.png 正如对应的DSL的文档中所阐述的,doFirst会将闭包中的操作放到Task列表的开头执行,而doLast则是会放到末尾,这时,就需要关注定义的顺序了

tasks.register('trueman')

tasks.named('trueman') {
    doLast {
        print 'Good afternoon'
    }
}

tasks.named('trueman') {
    doFirst {
        println "In case I don't see you..."
    }
}

tasks.named('trueman') {
    doLast {
        print ', good evening'
    }
}

tasks.named('trueman') {
    doLast {
        print ', and good night'
    }
}
$ gradle -q trueman
In case I don't see you...
Good afternoon,good evening,and good night

当前就只有trueman这一个Task,第二个定义的Action会在开头执行,其他使用doLast定义操作,根据顺序,依次排向末尾,按照定义的顺序执行 当然,如果改成doFirst有多个,那么就是后定义的反而会放到前面,因为doFirstdoLast只会从两端进入 image.png

5. 使用方法

即使是在其他编写业务逻辑的场景下,提取方法或者函数其实也是为了结构更加清晰,使得代码有更强的复用性
在编写构建脚本时,往往也有一些相似的操作场景可以进行方法的提取,从而将其批量地应用到多个构建过程中

// 输出符号表
tasks.register('readMapping') {
    doLast {
        printContent("C:\\Develop\\groovy_projects\\test\\mapping.txt")
    }
}
// 输出配置
tasks.register('readConfig') {
    doLast {
        printContent("C:\\Develop\\config\\test\\config.json")
    }
}
// 按路径读取文件,并输出内容
def printContent(String path) {
    def file = new File(path)
    file.eachLine {    // 将内容按行输出
        println it
    }
}

6. 默认Task

在没有指定具体的Task的时候,Gradle会运行定义的默认Task

defaultTasks('eat', 'relax')   // 定义了默认

tasks.register('relax') {
    doLast {
        println '摸鱼'
    }
}

tasks.register('eat') {
    doLast {
        println '干饭'
    }
}

tasks.register('work') {
    doLast {
        println '发奋图强'
    }
}
$ ./gradlew -q
干饭
摸鱼

这里运行的时候并没有指定某一个Task,那么这就会执行我们声明为默认的Task 如果处在一个多项目的构建中,每个子级项目可以定义子级的默认Task,如果没有,在未指定Task的情况下,那么会去找父级项目的默认Task

7. 构建脚本的外部依赖

出现了新角色,首先来看下buildscript{}这个块的文档 image.png 这个块所做的事情是为当前项目配置构建脚本的classpath,又出现了新的名词,待会再看
ScriptHandler作为闭包的委托被传给buildscript的闭包...(啥玩意) image.png 先查下ScriptHandler,它是个接口,主要的职责是为构建脚本的编译和执行提供管理
然后在这里,正好出现了classpath,它是用于编译和执行构建脚本的,另外也可以加载构建脚本用到的插件,在构建脚本编译前,这些依赖关系会被组装完成,至少大概了解它是做什么的了

尝试一下官方提供的实例,这里需要注意,buildscript{}的位置需要在构建脚本中的plugins{}声明之前

buildscript {
    repositories {  // 仓库
        mavenCentral()
    }
    dependencies {    // 依赖
        classpath group: 'commons-codec', name: 'commons-codec', version: '1.11'
    }
}

然后这里面的这两个块,repositories{}dependencies{}对应于ScriptHandler接口定义的两个方法 image.png image.png 这些注释简直如出一辙,这又是分别由DependencyHandlerRepositoryHandler来处理的 DependencyHandler将添加的依赖附加到classpath的配置当中,并且这些依赖在编译之前会被解析完成,汇编到脚本的classpath当中
并且,大多数的依赖需要为其声明对应的仓库,从而让RepositoryHandler能够从仓库中找到它们

在依赖被添加到classpath之后,就可以直接使用这些类了

tasks.register('encode') {
    doLast {
        byte[] encodedString = new Base64().encode('hello world\n'.getBytes())
        println new String(encodedString)
    }
}

注意,这里需要导下包,平常都是IDE帮忙,这里别忘了

import org.apache.commons.codec.binary.Base64  // 导包

输出结果

$ ./gradlew -q encode
aGVsbG8gd29ybGQK

如果构建多个模块的项目,那么外层的项目级中声明buildscript{},下层的模块是都可以进行共享的

调用buildEnvironment可以查看依赖的解析情况,这是每一个项目中都会自带的一个Task

$ ./gradlew -q buildEnvironment

image.png

这就是你的classpath中解析的各种依赖

Gradle DSL Version 7.3