每一個 Gradle 構建都會按照相同的順序經歷三個不同的階段:初始化、配置、執行。 ...
兩個重要的概念
項目
實際上,一個項目是什麼取決於你要用 Gradle 做什麼?項目通常代表的是構建內容。 例如在 Android 中,一個 module 就是一個項目;
- 項目是註冊在 setting.gradle 中的
- 通常一個項目有一個 build.gradle
Gradle 構建就是由一個或多個項目組成的。
任務
任務 顧名思義就是一個在構建階段被執行的操作。它是 Gradle 構建的原子工作單位。例如 編譯 Java 源代碼;
任務是定義在項目的構建腳本中,並且可以彼此依賴。
一個項目就是由一個個任務組成的。
每一個 Gradle 構建都會按照相同的順序經歷三個不同的階段:
初始化
Gradle 支持單項目構建和多項目構建。
在這個階段 Gradle 會確認哪些項目將會參與構建。Gradle 會通過 setting.gradle 確定是多項目還是單項目構建。
Gradle 會為每個項目創建 Project 實例。
配置
在這個階段執行在初始化階段中確定的每一個項目的配置腳本,但是並不會執行其中的任務,只會評估任務的依賴性,根據其依賴性創建任務的有向無環圖。
Gradle引入了一個稱為隨需求變配置的特性,該特性使它能夠在構建過程中只配置相關和必要的項目。這在大型多項目構建中非常有用,因為它可以大大減少構建時間。
執行
在這個階段,Gradle 會識別在配置階段創建的任務的有向無環圖。並按照他們的依賴順序開始執行。
所有的構建工作都是在這個階段執行的。如編譯源碼,生成 .class 文件,複製文件等。
setting.gradle
這個文件是由 Gradle 約定命名的,預設名為 setting.gradle ,在初始化階段被執行。
對於多項目構建,必須在這裡聲明要參與構建的所有項目。對於單項目構建就是可選的了,可有可無。
Gradle 是如何尋找 setting.gradle 的?
- 在當前目錄尋找
- 沒有找到的話就去父目錄尋找
- 仍然沒有找到就是是單項目構建了
- 如果找到了就是確定其中的項目,如果當前執行的項目在 setting.gradle 有定義就執行多項目構建,否則就執行單項目構建。
一個腳本的屬性訪問和方法調用是委托給 Project 類的實例的,類似的 setting.gradle 的屬性訪問和方法調用是委托給 Settings 類的實例對象的。
單項目構建
對於單項目構建,在初始化後的工作流程很簡單,構建腳本針對初始化階段創建的項目對象執行。查找在命令行傳入的任務名稱相同的任務。
如果任務存在則作為一個單獨的構建按照命令行傳遞的順序執行。
多項目構建
多項目構建是在 Gradle 的單個執行過程中構建多個項目的構建。必須把參與構建的項目聲明在 setting.gradle 里
項目位置
可以把多項目構建看作一個單根的樹。每一個項目都是樹上的一個節點。一個項目有一個路徑表示在樹中的位置。
通常情況下項目的路徑和在文件系統中的位置是一致的,當然了這個路徑也是可以配置的。
項目樹是 setting.gradle 生成的,預設情況下 setting.gradle 的位置就是根項目的位置。但是你可以在 setting.gradle 文件中更改。
構建項目樹
在 setting.gradle 設置文件中你可以使用一些列的方法配置構建項目樹。分層和平面物理佈局都支持。
分層佈局
Groovy
include 'project1', 'project2:child', 'project3:child1'
Kotlin
include("project1", "project2:child", "project3:child1")
include 方法使用項目路徑作為參數,假定項目路徑與相對物理文件系統路徑相等。
例如 "project2:child" 預設對應的是相對於根目錄的 "project2/child"。
這也意味著包含路徑 “services:hotels:api” 將創建3個項目:
- “services”
- “services:hotels”
- “services:hotels:api”
更詳細的說明可以 DSL文檔
平面佈局
Groovy
includeFlat 'project3', 'project4'
Kotlin
includeFlat("project3", "project4")
includeFlat 也是目錄名字作為參數。這些目錄要和根項目目錄同級。
這些目錄的位置在項目樹中是根項目的子項目。
更改項目樹的元素
在設置文件中創建的多項目樹由所謂的項目描述符組成。這些項目符號可以隨時更改。
可以通過下麵這種方式訪問描述符
查找項目樹的元素
Groovy
println rootProject.name
println project(':projectA').name
Kotlin
println(rootProject.name)
println(project(":projectA").name)
使用這個描述符你可以一個項目的名字,項目目錄和構建文件
更改項目樹元素
Groovy
rootProject.name = 'main'
project(':projectA').projectDir = new File(settingsDir, '../my-project-a')
project(':projectA').buildFileName = 'projectA.gradle'
Kotlin
rootProject.name = "main"
project(":projectA").projectDir = File(settingsDir, "../my-project-a")
project(":projectA").buildFileName = "projectA.gradle"
更詳細的信息可以查看 ProjectDescriptor 類的 API 文檔。
接收生命周期事件
構建腳本可以接收生命周期構建進度的通知。
接收這些通知一般是兩種形式
- 實現詳細的監聽介面
- 在發送通知時提供一個閉包來執行
項目評估事件
可以在項目評估後馬上接到事件通知 使用的是 Project.afterEvaluate 方法,傳入一個閉包,Gradle會將評估的項目和狀態傳遞進閉包里。
Kotlin
afterEvaluate {
println("${project.getName()} 評估結果:${state.getExecuted()}")
}
Groovy
afterEvaluate{ project,state->
println "$project 評估成功否:${state.failure==null}"
}
如果是在多項目構建里,可以在 allprojects 的閉包里使用,這樣每個項目的評估事件就都接受到了
Groovy
allprojects{
afterEvaluate{ project,state->
println "$project 評估成功否:${state.failure==null}"
}
}
評估前的事件通知使用 Project.beforeEvaluate 照樣是傳入一個閉包,Gradle會將要評估的項目傳遞進閉包里
Groovy
allprojects{
afterEvaluate{ project,state->
println "$project 評估成功否:${state.failure==null}"
}
beforeEvaluate { project ->
println "開始評估 $project"
}
}
這裡列出了使用的 api文檔。
任務
任務被添加到項目
Groovy
tasks.whenTaskAdded { task ->
println "$task 被添加到項目了。"
}
Kotlin
tasks.whenTaskAdded {
extra["srcDir"] = "src/main/java"
}
val a by tasks.registering
println("source dir is ${a.get().extra["srcDir"]}")
有向無環圖填充完畢
使用的是 TaskExecutionGraph.whenReady 方法
Groovy
gradle.taskGraph.whenReady{ graph->
println "任務圖準備好了:\n"
graph.allTasks.each {
print "$it , "
}
}
任務執行
Groovy
task ok
task broken(dependsOn: ok) {
doLast {
throw new RuntimeException('broken')
}
}
gradle.taskGraph.beforeTask { Task task ->
println "executing $task ..."
}
gradle.taskGraph.afterTask { Task task, TaskState state ->
if (state.failure) {
println "FAILED"
}
else {
println "done"
}
}
這裡留一個Gradle API 的查詢地址
文檔參考
- https://docs.gradle.org/current/userguide/build_lifecycle.html
- https://proandroiddev.com/understanding-gradle-the-build-lifecycle-5118c1da613f