持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
前言
在编写Gradle脚本时,需要调用大量API来完成你预想的需求,Project接口在官网是这样说的:此接口是用于从构建文件与 Gradle 交互的主要 AP,可以通过编程访问Gradle的所有功能。
所以先从Project接口下的方法开始介绍。
Project
afterEvaluate
看名字意思是之后评估,似乎很难理解是什么意思,他是用于在配置项目后进行回调,当然还有一个在之前回调的方法beforeEvaluate,但beforeEvaluate必须在父模块的 build.gradle 对子模块进行配置才能生效,因为在当前模块的 build.gradle 中配置,它自己本身都没配置好,所以不会监听到。
this.afterEvaluate {
println("afterEvaluate")
}
copy
用来复制文件,如下,作用是把/home/HouXinLin/test/a.txt这个文件复制到当前目录
task taskA(){
doLast {
this.copy {
from("/home/HouXinLin/test/a.txt")
into "./"
}
}
}
当然也可以使用通配符,如下,用来把目标文件夹下所有文件复制到当前目录下的test下,include用来做包含,**表示所有文件。
task taskA(){
doLast {
this.copy {
from("/home/HouXinLin/test/"){
include "**"
}
into "./test/"
}
}
}
from这个函数是由CopySpec提供,可以事先创建一个CopySpec对象,然后创建一个type为Copy的任务,进行复制。
def baseCopy =copySpec {
from("/home/HouXinLin/test/")
include "**"
}
task taskA(type:Copy){
into "./test"
with baseCopy
}
delete
用于删除文件,如下,用于删除当前目录下test文件夹和其中所有文件。
task taskA(){
doLast {
this.delete("./test")
}
}
exec
执行外部命令,如执行ls命令,executable用于指定命令名称,args代表参数。
task taskA(){
doLast {
println(this.exec {
executable("ls")
args("-l")
})
}
}
还可以通过type指定任务为Exec,workingDir设置工作目录,commandLine设置命令,如下,使用touch命令创建一个test.txt文件。
task taskA(type:Exec){
workingDir("./test")
commandLine("touch","test.txt")
}
file
创建一个文件对象,返回值就是File,可以调用其任意方法,参数不仅仅可以是字符串,还可以是File、Path、URL
task taskA(){
doLast {
def testFile =file("./test/test.txt")
println(testFile.path)
}
}
getBuildDir()
返回此项目的构建目录。
task taskA(){
doLast {
println(this.getBuildDir())
}
}
getBuildFile()
此项目的构建脚本路径。
task taskA(){
doLast {
println(this.getBuildFile())
}
}
getRootDir()
返回此项目根目录
task taskA(){
doLast {
println(this.getRootDir())
}
}
getVersion()
返回此项目版本,如果不写version,则返回unspecified。
version("1.1")
task taskA(){
doLast {
println(this.getVersion())
}
}
mkdir
创建目录。
task taskA(){
doLast {
mkdir("./a")
}
}
task
根据给定名称创建一个Task, 并将其添加到此项目中,如下,在配置阶段创建一个testB,并设置testA依赖testB,这样在执行testA时,会自动先执行testB。
task taskA(){
task("testB"){
doLast {
println("testB")
}
}
doLast {
println("taskA")
}
tasks.taskA.dependsOn("testB")
}
configurations
负责声明和管理配置,配置叫Configuration,而他表示一个artifacts或者其他依赖项。
如下,可以遍历现有的配置。
task taskA(){
doLast {
configurations.configureEach{
println(it.name)
}
}
}
输出如下
annotationProcessor
apiElements
archives
compileClasspath
compileOnly
default
implementation
mainSourceElements
runtimeClasspath
runtimeElements
runtimeOnly
testAnnotationProcessor
testCompileClasspath
testCompileOnly
testImplementation
testResultsElementsForTest
testRuntimeClasspath
testRuntimeOnly
如果已经使用过Gradle的人来说,看到这些会非常熟悉,这些都是用来引入一个依赖的。
但是他们都有区别,比如runtimeOnly意为只有在运行时候引入,而compileOnly意为只有在编译时引入,最常用的就是implementation,表示在编译和运行时都引入,configurations是ConfigurationContainer的实例,他所提供的create方法可以让我们创建一个类似implementation的功能,如下所示。
configurations.create("testConfig")
这样在使用刚才代码遍历时,就会出现testConfig,同时我们可以在dependencies下使用他,如下
configurations.create("testConfig")
task taskA(){
doLast {
configurations.testConfig.getFiles().forEach{
println(it.absolutePath)
}
}
}
repositories {
mavenCentral()
}
dependencies {
testConfig group: 'mysql', name: 'mysql-connector-java', version: '8.0.29'
testConfig files("./test/test.txt")
}
通过configurations.testConfig.getFiles()就可以拿到所有通过testConfig引入的依赖,注意,除了jar我们称之为依赖,其他文件也当然算依赖了,然后拿到依赖路径后就可以做下一步逻辑了,但上面会输出三个路径,可明明只引入了2个,为什么会输出三个路径呢?
因为依赖还可以依赖其他第三方依赖,上面我们引入的mysql驱动,他里面还依赖了protobuf-java这个jar包,所以会输出三个路径。
下面介绍一个常用的功能,排除依赖,拿上面来说,我们把protobuf-java排除掉,可以这样做。
configurations.create("testConfig")
configurations {
testConfig.exclude group:"com.google.protobuf",module:"protobuf-java"
}
task taskA(){
doLast {
configurations.testConfig.getFiles().forEach{
println(it.absolutePath)
}
}
}
repositories {
mavenCentral()
}
dependencies {
testConfig group: 'mysql', name: 'mysql-connector-java', version: '8.0.29'
testConfig files("./test/test.txt")
}
这样输出就只有两个文件了,但这样属于全局排除,任何一个依赖引入了protobuf-java都会排除,其实还可以针对单个依赖,可以这样做。
testConfig (group: 'mysql', name: 'mysql-connector-java', version: '8.0.29'){
exclude group:"com.google.protobuf",module:"protobuf-java"
}
关于依赖管理我们在后续文章单独说。
zipTree
通常在打包jar的时候需要,如把第三方依赖解压后放入主工程中,zipTree用来根据一个zip文件,创建一个FileTree,其中包含这个zip中的所有文件,这时候可以使用copy、into去解压。
task taskA(){
doLast {
copy {
from zipTree('/home/HouXinLin/test/maven-demo-1.0.jar')
into './test'
}
}
}
还有个tarTree也是类似。
javaexec
用于启动java进程,如下。
task taskA(){
doLast {
javaexec{
classpath("/home/HouXinLin/test/maven-demo-1.0.jar")
mainClass="com.hxl.Main"
}
}
}
关于Project的API就到这里。
Task
Task是关于任务的接口。
dependsOn
用于依赖其他任务,如下,用于将taskB依赖taskA。
task taskA(){
doFirst {
println("taskA")
}
}
task taskB(){
doFirst {
println("taskB")
}
}
tasks.getByName("taskB").configure {
dependsOn("taskA")
}
tasks是Project中提供的方法,用于获取TaskContainer,他负责管理Task,getByName则是根据名字获取任务。
configure用于配置任务。
doFirst
用于将给定的闭包添加到此任务的操作列表的开头,可以执行多次,把他想象成一个队列,每次doFirst的时候向队列前面添加一个闭包
task taskB(){
doFirst {
println("taskB1")
}
}
tasks.getByName("taskB").configure {
doFirst {
println("taskB2")
}
doFirst {
println("taskB3")
}
}
在上面,第一个doFirst是taskB中配置的,将打印taskB1,而顺着书写顺序,又新增加了一个doFirst,打印taskB2,最后又增加了一个,打印taskB3,所以,第一个应该执行最后一个添加的doFirst,所以最终结果如下。
taskB3
taskB2
taskB1
doFirst也是类似。
finalizedBy
用于添加一个最终执行的任务,和java中的finally一样,也就是当本任务执行后,执行一个最终的任务。
task taskA(){
doFirst {
println("taskA")
}
}
task taskB(){
doFirst {
println("taskB1")
}
}
tasks.getByName("taskB").configure {
finalizedBy("taskA")
}
getActions
Task由一堆Action对象组成,就是doFirst或者doLast中的代码块,抽象成了Action,当任务执行时,每个Action依次执行,可以通过Action.execute(T)手动调用,而getActions就是获取这个任务的所有Action。
如下,我们在配置阶段获取了taskB的所有Action,然后依次手动调用每个doFirst和doLast代码块。
task taskB(){
doFirst {
println("doFirst")
}
doLast {
println("doLast")
}
}
tasks.getByName("taskB").configure {
getActions().forEach{
it.execute(tasks.getByName("taskB"))
}
}
当taskB执行时,相当于执行了2次。
onlyIf
onlyIf需要一个返回值,如果为true,则表示这个任务可以执行,如果为false,那么这个任务将不执行。
task taskB(){
doFirst {
println("doFirst")
}
}
tasks.getByName("taskB").configure {
onlyIf {
return 1>2
}
}