文章目录
每一个 build.gradle
脚本文件被 Gradle
加载解析后,都会对应生成一个 Project
对象。在脚本中的配置方法其实都对应着 Project
中的API
,如果想详细了解这些脚本的配置含义,有必要对 Project
类做些深入的剖析。
Project类图
当构建进程启动后,Gradle
基于build.gradle
中的配置实例化org.gradle.api.Project
类,先来看看 Project
类的主要结构(节选部分常用):
接下来我们通过一些实际的例子,由浅入深的来体会这些 API 的含义。
getter/setter属性
File bd = getBuildDir()
println "buildDir = ${bd.getAbsolutePath()}"
//获取Project的名字
String name = getName()
println "project name = $name"
//设置Project的描述信息
setDescription "这是一个测试案例"
String desc = getDescription()
println "project description = $desc"
//获取Project的路径
String path = getPath();
println "project path = $path"
class VersionInfo {
String version
boolean release
VersionInfo(String v, boolean release) {
version = v
this.release = release
}
String toString() {
return "V-${version}-${release ? 'release' : 'debug'}"
}
}
//设置Project的版本号,参数可以是任何对象,gradle内部会使用 toString() 方法返回的值
setVersion(new VersionInfo("1.0.0", true))
println("project version = ${getVersion()}")
//设置Project的分组
setGroup "TestGroup"
println("project group = ${getGroup()}")
直接执行 gradle
命令,可以看到在配置阶段
输出以下结果:
> Configure project :
rootDir = /Users/hjy/Desktop/gradle
buildDir = /Users/hjy/Desktop/testgradle/build
project name = gradle
project description = 这是一个测试案例
project path = :
project version = V-1.0.0-release
project group = TestGroup
创建task
我们在 build.gradle
文件中定义 task
的方式,其实都对应的是 Project
类中的 task()
方法,从 Project
类图中的 task API
可以看到有多种不同的形式,前面介绍 task
的章节已经介绍过了,这里就不赘述了。
文件操作
通过mkdir创建目录
File mkDir = mkdir("${buildDir}/test");
File mkDir2 = mkdir("${buildDir}/test2")
println "检测目录是否创建成功:${mkDir.exists()}, ${mkDir2.exists()}"
通过file、files 定位文件
//定位单个文件,参数可以是相对路径、绝对路径
File testDir = file("${buildDir}/test")
println "文件定位是否成功:${testDir.exists()}"
//文件集合,Gradle里用 FileCollection 来表示
FileCollection fileCollection = files("${buildDir}/test", "${buildDir}/test2")
println "-------对文件集合进行迭代--------"
fileCollection.each {File f ->
println f.name
}
println "-------文件迭代结束-------"
//获取文件列表
Set<File> set = fileCollection.getFiles()
println "文件集合里共有${set.size()}个文件"
通过fileTree创建文件树
Gradle
里用 ConfigurableFileTree
来表示文件树,文件树会返回某个目录及其子目录下所有的文件,不包含目录。
//先在build目录下创建3个txt文件
file("${buildDir}/t1.txt").createNewFile()
file("${buildDir}/test/t2.txt").createNewFile()
file("${buildDir}/t1.java").createNewFile()
//1.通过一个基准目录创建文件树,参数可以是相对目录,也可以是绝对目录,与file()方法一样
println "通过基准目录来创建文件树"
ConfigurableFileTree fileTree1 = fileTree("build")
//添加包含规则
fileTree1.include "*.txt", "*/*.txt"
//添加排除规则
fileTree1.exclude "*.java"
fileTree1.each { f ->
println f
}
//2.通过闭包来创建文件树
println "通过闭包来创建文件树"
ConfigurableFileTree fileTree2 = fileTree("build") {
include "*/*.txt", "*.java"
exclude "*.txt"
}
fileTree2.each { f ->
println f
}
//3.通过map配置来创建文件树,可配置的选项有:dir: ''、include: '[]、exclude: []、includes: []、excludes: []
println "通过Map来创建文件树"
def fileTree3 = fileTree(dir: "build", includes: ["*/*.txt", "*.java"])
fileTree3 = fileTree(dir: "build", exclude: "*.java")
fileTree3.each { f ->
println f
}
复制文件
复制文件需要使用复制任务(Copy
)来进行,它需要指定要复制的源文件和一个目标目录,复制的规则都是定义在 CopySpec
接口里的,更详细的说明可参见 API
文档。
task testCopyFile(type: Copy) {
//复制build目录下的所有文件
from "build"
//复制单独的某个文件
from "test.java"
//复制某个文件树下的所有文件
from fileTree("build")
include "*.txt"
include "*.java"
exclude "t1.txt"
//指定目标目录
into "outputs"
//对复制的文件重命名:通过闭包来映射
rename { fileName ->
//增加 rename_ 前缀
return fileName.endsWith(".java") ? "rename_" + fileName : fileName
}
//通过正则来映射文件名:abctest.java 会映射成 abchjy.java
rename '(.*)test(.*)', '$1hjy$2'
}
删除文件
//删除 build 目录下所有文件
delete("${buildDir}")
多项目构建
前面我们介绍的例子,都是单独执行某一个 build.gradle
文件。但是我们在 Android
应用开发中,一个 Project
可以包含若干个 module
,这种就叫做多项目构建。在 Android Studio
项目中,根目录都有一个名叫 settings.gradle
的文件,然后每个 module
的根目录中又有一个 build.gradle
文件,Gradle
就是通过 settings.gradle
来进行多项目构建的。
- 通过 settings.gradle 引入子项目
如图所示,在项目根目录创建一个settings.gradle
,在根目录、app以及library
目录下也都创建一个build.gradle
文件。 - 在 settings.gradle 里引入子项目
include ":app", ":library"
- 在 build.gradle 里增加测试代码
//在根目录 build.gradle 里增加
println "-----root file config-----"
//在 app/build.gradle 里增加
println "-----app config-----"
//在 library/build.gradle 里增加
println "-----library config-----"
- 在项目根目录执行命令
gradle -q
,结果如下:
-----root file config-----
-----app config-----
-----library config-----
这是一个多项目构建的简单例子,可以看到结构与我们的 Android
项目是类似的。Gradle
在运行时会读取并解析 settings.gradle
文件,生成一个 Settings``对象,然后从中读取并解析子项目的 build.gradle
文件,然后为每个 build.gradle
文件生成一个 Project
对象,进而组装一个多项目构建出来。
Settings
里最核心的API
就是 include
方法,通过该方法引入需要构建的子项目。
include(projectPaths: String...)
这里我们为每个 build.gradle
文件生成了一个 Project
对象,跟总共3个 Project
,根目录的 Project
我们称之为 root project
,子目录的 Project
我们称之为 child project
。
项目配置
在根项目里可以对子项目进行配置:
//通过path定位并获取该 Project 对象
project(path: String): Project
//通过path定位一个Project,并进行配置
project(path: String, config: Closure): Project
//针对所有项目进行配置
allprojects(config: Closure)
//针对所有子项目进行配置
subprojects(config: Closure)
我们修改根目录 build.gradle
文件如下:
println "-----root file config-----"
//配置 app 项目
project(":app") {
ext {
appParam = "test app"
}
}
//配置所有的项目
allprojects {
ext {
allParam = "test all project"
}
}
//配置子项目
subprojects {
ext {
subParam = "test sub project"
}
}
println "allParam = ${allParam}"
修改 app/build.gradle
文件如下:
println "-----app config-----"
println "appParam = ${appParam}"
println "allParam = ${allParam}"
println "subParam = ${subParam}"
修改 library/build.gradle
文件如下:
println "-----library config-----"
println "allParam = ${allParam}"
println "subParam = ${subParam}"
运行结果如下:
-----root file config-----
allParam = test all project
-----app config-----
appParam = test app
allParam = test all project
subParam = test sub project
-----library config-----
allParam = test all project
subParam = test sub project
构建脚本配置
buildscript
配置该 Project
的构建脚本的 classpath
,在 Andorid Studio
中的 root project
中可以看到:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}
apply
apply(options: Map<String, ?>)
我们通过该方法使用插件或者是其他脚本,options
里主要选项有:
- from: 使用其他脚本,值可以为
Project.uri(Object)
支持的路径 - plugin:使用其他插件,值可以为插件
id
或者是插件的具体实现类
例如:
//使用插件,com.android.application 就是插件id
apply plugin: 'com.android.application'
//使用插件,MyPluginImpl 就是一个Plugin接口的实现类
apply plugin: MyPluginImpl
//引用其他gradle脚本,push.gradle就是另外一个gradle脚本文件
apply from: './push.gradle'
属性
Gradle属性
在与 build.gradle
文件同级目录下,定义一个名为 gradle.properties
文件,里面定义的键值对,可以在 Project
中直接访问。
//gradle.properties里定义属性值
company="hangzhouheima"
username="hjy"
在 build.gradle
文件里可以这样直接访问:
println "company = ${company}"
println "username = ${username}"
ext扩展属性
还可以通过 ext
命名空间来定义属性,我们称之为扩展属性。
ext {
username = "hjy"
age = 30
}
println username
println ext.age
println project.username
println project.ext.age
必须注意,默认的扩展属性,只能定义在 ext
命名空间下面。对扩展属性的访问方式,以上几种都支持。