每一個 build.gradle 腳本文件被 Gradle 加載解析后,都會對應(yīng)生成一個 Project 對象,在腳本中的配置方法其實都對應(yīng)著 Project 中的API,如果想詳細了解這些腳本的配置含義,有必要對 Project 類做些深入的剖析。
1. Project類圖
當構(gòu)建進程啟動后,Gradle基于build.gradle中的配置實例化org.gradle.api.Project類,先來看看 Project 類的主要結(jié)構(gòu)(節(jié)選部分常用):

接下來我們通過一些實際的例子,由淺入深的來體會這些 API 的含義。
2. getter/setter屬性
File bd = getBuildDir()
println "buildDir = ${bd.getAbsolutePath()}"
//獲取Project的名字
String name = getName()
println "project name = $name"
//設(shè)置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'}"
}
}
//設(shè)置Project的版本號,參數(shù)可以是任何對象,gradle內(nèi)部會使用 toString() 方法返回的值
setVersion(new VersionInfo("1.0.0", true))
println("project version = ${getVersion()}")
//設(shè)置Project的分組
setGroup "TestGroup"
println("project group = ${getGroup()}")
直接執(zhí)行 gradle 命令,可以看到在配置階段輸出以下結(jié)果:
> 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
2. 創(chuàng)建task
我們在 build.gradle 文件中定義 task 的方式,其實都對應(yīng)的是 Project 類中的 task() 方法,從 Project 類圖中的 task API 可以看到有多種不同的形式,前面介紹 task 的章節(jié)已經(jīng)介紹過了,這里就不贅述了。
3. 文件操作
3.1 通過mkdir創(chuàng)建目錄
File mkDir = mkdir("${buildDir}/test");
File mkDir2 = mkdir("${buildDir}/test2")
println "檢測目錄是否創(chuàng)建成功:${mkDir.exists()}, ${mkDir2.exists()}"
3.2 通過file、files 定位文件
//定位單個文件,參數(shù)可以是相對路徑、絕對路徑
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 "-------文件迭代結(jié)束-------"
//獲取文件列表
Set<File> set = fileCollection.getFiles()
println "文件集合里共有${set.size()}個文件"
3.3 通過fileTree創(chuàng)建文件樹
Gradle里用 ConfigurableFileTree 來表示文件樹,文件樹會返回某個目錄及其子目錄下所有的文件,不包含目錄。
//先在build目錄下創(chuàng)建3個txt文件
file("${buildDir}/t1.txt").createNewFile()
file("${buildDir}/test/t2.txt").createNewFile()
file("${buildDir}/t1.java").createNewFile()
//1.通過一個基準目錄創(chuàng)建文件樹,參數(shù)可以是相對目錄,也可以是絕對目錄,與file()方法一樣
println "通過基準目錄來創(chuàng)建文件樹"
ConfigurableFileTree fileTree1 = fileTree("build")
//添加包含規(guī)則
fileTree1.include "*.txt", "*/*.txt"
//添加排除規(guī)則
fileTree1.exclude "*.java"
fileTree1.each { f ->
println f
}
//2.通過閉包來創(chuàng)建文件樹
println "通過閉包來創(chuàng)建文件樹"
ConfigurableFileTree fileTree2 = fileTree("build") {
include "*/*.txt", "*.java"
exclude "*.txt"
}
fileTree2.each { f ->
println f
}
//3.通過map配置來創(chuàng)建文件樹,可配置的選項有:dir: ''、include: '[]、exclude: []、includes: []、excludes: []
println "通過Map來創(chuàng)建文件樹"
def fileTree3 = fileTree(dir: "build", includes: ["*/*.txt", "*.java"])
fileTree3 = fileTree(dir: "build", exclude: "*.java")
fileTree3.each { f ->
println f
}
3.4 復(fù)制文件
復(fù)制文件需要使用復(fù)制任務(wù)(Copy)來進行,它需要指定要復(fù)制的源文件和一個目標目錄,復(fù)制的規(guī)則都是定義在 CopySpec 接口里的,更詳細的說明可參見 API 文檔。
task testCopyFile(type: Copy) {
//復(fù)制build目錄下的所有文件
from "build"
//復(fù)制單獨的某個文件
from "test.java"
//復(fù)制某個文件樹下的所有文件
from fileTree("build")
include "*.txt"
include "*.java"
exclude "t1.txt"
//指定目標目錄
into "outputs"
//對復(fù)制的文件重命名:通過閉包來映射
rename { fileName ->
//增加 rename_ 前綴
return fileName.endsWith(".java") ? "rename_" + fileName : fileName
}
//通過正則來映射文件名:abctest.java 會映射成 abchjy.java
rename '(.*)test(.*)', '$1hjy$2'
}
3.5 刪除文件
//刪除 build 目錄下所有文件
delete("${buildDir}")
4. 多項目構(gòu)建
前面我們介紹的例子,都是單獨執(zhí)行某一個 build.gradle 文件。但是我們在 Android 應(yīng)用開發(fā)中,一個 Project 可以包含若干個 module ,這種就叫做多項目構(gòu)建。在 Android Studio 項目中,根目錄都有一個名叫 settings.gradle 的文件,然后每個 module 的根目錄中又有一個 build.gradle 文件,Gradle 就是通過 settings.gradle 來進行多項目構(gòu)建的。
4.1 通過 settings.gradle 引入子項目
1.先創(chuàng)建如下幾個目錄及文件:

如圖所示,在項目根目錄創(chuàng)建一個 settings.gradle,在根目錄、app以及l(fā)ibrary目錄下也都創(chuàng)建一個 build.gradle 文件。
2.在 settings.gradle 里引入子項目
include ":app", ":library"
3.在 build.gradle 里增加測試代碼
//在根目錄 build.gradle 里增加
println "-----root file config-----"
//在 app/build.gradle 里增加
println "-----app config-----"
//在 library/build.gradle 里增加
println "-----library config-----"
4.在項目根目錄執(zhí)行命令 gradle -q,結(jié)果如下:
-----root file config-----
-----app config-----
-----library config-----
這是一個多項目構(gòu)建的簡單例子,可以看到結(jié)構(gòu)與我們的 Android 項目是類似的。Gradle 在運行時會讀取并解析 settings.gradle 文件,生成一個 Settings對象,然后從中讀取并解析子項目的 build.gradle 文件,然后為每個 build.gradle 文件生成一個 Project 對象,進而組裝一個多項目構(gòu)建出來。
Settings 里最核心的API就是 include 方法,通過該方法引入需要構(gòu)建的子項目。
include(projectPaths: String...)
這里我們?yōu)槊總€ build.gradle 文件生成了一個 Project 對象,跟總共3個 Project,根目錄的 Project 我們稱之為 root project,子目錄的 Project 我們稱之為 child project。
4.2 項目配置
在根項目里可以對子項目進行配置:
//通過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}"
運行結(jié)果如下:
-----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
5. 構(gòu)建腳本配置
5.1 buildscript
配置該 Project 的構(gòu)建腳本的 classpath,在 Andorid Studio 中的 root project 中可以看到:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.1'
}
}
5.2 apply
apply(options: Map<String, ?>)
我們通過該方法使用插件或者是其他腳本,options里主要選項有:
- from: 使用其他腳本,值可以為 Project.uri(Object) 支持的路徑
- plugin:使用其他插件,值可以為插件id或者是插件的具體實現(xiàn)類
例如:
//使用插件,com.android.application 就是插件id
apply plugin: 'com.android.application'
//使用插件,MyPluginImpl 就是一個Plugin接口的實現(xiàn)類
apply plugin: MyPluginImpl
//引用其他gradle腳本,push.gradle就是另外一個gradle腳本文件
apply from: './push.gradle'
6. 屬性
6.1 Gradle屬性
在與 build.gradle 文件同級目錄下,定義一個名為 gradle.properties 文件,里面定義的鍵值對,可以在 Project 中直接訪問。
//gradle.properties里定義屬性值
company="hangzhouheima"
username="hjy"
在 build.gradle 文件里可以這樣直接訪問:
println "company = ${company}"
println "username = ${username}"
6.2 擴展屬性
還可以通過 ext 命名空間來定義屬性,我們稱之為擴展屬性。
ext {
username = "hjy"
age = 30
}
println username
println ext.age
println project.username
println project.ext.age
必須注意,默認的擴展屬性,只能定義在 ext 命名空間下面。對擴展屬性的訪問方式,以上幾種都支持。
系列文章
Android Gradle學(xué)習(xí)(一):Gradle基礎(chǔ)入門
Android Gradle學(xué)習(xí)(二):如何創(chuàng)建Task
Android Gradle學(xué)習(xí)(三):Task進階學(xué)習(xí)
Android Gradle學(xué)習(xí)(四):Project詳解
Android Gradle學(xué)習(xí)(五):Extension詳解
Android Gradle學(xué)習(xí)(六):NamedDomainObjectContainer詳解
Android Gradle學(xué)習(xí)(七):Gradle構(gòu)建生命周期
Android Gradle學(xué)習(xí)(八):統(tǒng)計Task執(zhí)行時長
Android Gradle學(xué)習(xí)(九):一些有用的小技巧