Gradle-構建生命周期
- 2019 年 12 月 11 日
- 筆記
兩個重要的概念
項目
實際上,一個項目是什麼取決於你要用 Gradle 做什麼?項目通常代表的是構建內容。 例如在 Android 中,一個 module 就是一個項目;
- 項目是註冊在 settings.gradle 中的
- 通常一個項目有一個 build.gradle
Gradle 構建就是由一個或多個項目組成的。
任務
任務 顧名思義就是一個在構建階段被執行的操作。它是 Gradle 構建的原子工作單位。例如 編譯 Java 源代碼;
任務是定義在項目的構建腳本中,並且可以彼此依賴。
一個項目就是由一個個任務組成的。
生命周期
每一個 Gradle 構建都會按照相同的順序經歷三個不同的階段:
初始化
Gradle 支持單項目構建和多項目構建。 在這個階段 Gradle 會確認哪些項目將會參與構建。Gradle 會通過 settings.gradle 確定是多項目還是單項目構建。 Gradle 會為每個項目創建 Project 實例。
配置
在這個階段執行在初始化階段中確定的每一個項目的配置腳本,但是並不會執行其中的任務,只會評估任務的依賴性,根據其依賴性創建任務的有向無環圖。
Gradle引入了一個稱為隨需求變配置的特性,該特性使它能夠在構建過程中只配置相關和必要的項目。這在大型多項目構建中非常有用,因為它可以大大減少構建時間。
執行
在這個階段,Gradle 會識別在配置階段創建的任務的有向無環圖。並按照他們的依賴順序開始執行。 所有的構建工作都是在這個階段執行的。如編譯源碼,生成 .class 文件,複製文件等。
setting.gradle
這個文件是由 Gradle 約定命名的,默認名為 settings.gradle ,在初始化階段被執行。
對於多項目構建,必須在這裡聲明要參與構建的所有項目。對於單項目構建就是可選的了,可有可無。
Gradle 是如何尋找 settings.gradle 的?
- 在當前目錄尋找
- 沒有找到的話就去父目錄尋找
- 仍然沒有找到就是是單項目構建了
- 如果找到了就是確定其中的項目,如果當前執行的項目在 settings.gradle 有定義就執行多項目構建,否則就執行單項目構建。
一個腳本的屬性訪問和方法調用是委託給 Project 類的實例的,類似的 settings.gradle 的屬性訪問和方法調用是委託給 Settings 類的實例對象的。
單項目構建
對於單項目構建,在初始化後的工作流程很簡單,構建腳本針對初始化階段創建的項目對象執行。查找在命令行傳入的任務名稱相同的任務。 如果任務存在則作為一個單獨的構建按照命令行傳遞的順序執行。
多項目構建
多項目構建是在 Gradle 的單個執行過程中構建多個項目的構建。必須把參與構建的項目聲明在 settings.gradle 里
項目位置
可以把多項目構建看作一個單根的樹。每一個項目都是樹上的一個節點。一個項目有一個路徑表示在樹中的位置。 通常情況下項目的路徑和在文件系統中的位置是一致的,當然了這個路徑也是可以配置的。 項目樹是 settings.gradle 生成的,默認情況下 settings.gradle 的位置就是根項目的位置。但是你可以在 settings.gradle 文件中更改。
構建項目樹
在 settings.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


