Gradle-構建生命周期


兩個重要的概念

項目

實際上,一個項目是什么取決於你要用 Gradle 做什么?項目通常代表的是構建內容。 例如在 Android 中,一個 module 就是一個項目;

  • 項目是注冊在 settings.gradle 中的
  • 通常一個項目有一個 build.gradle

Gradle 構建就是由一個或多個項目組成的。

任務

任務 顧名思義就是一個在構建階段被執行的操作。它是 Gradle 構建的原子工作單位。例如 編譯 Java 源代碼;

任務是定義在項目的構建腳本中,並且可以彼此依賴。

一個項目就是由一個個任務組成的。

每一個 Gradle 構建都會按照相同的順序經歷三個不同的階段:

初始化

Gradle 支持單項目構建和多項目構建。
在這個階段 Gradle 會確認哪些項目將會參與構建。Gradle 會通過 settings.gradle 確定是多項目還是單項目構建。
Gradle 會為每個項目創建 Project 實例。

配置

在這個階段執行在初始化階段中確定的每一個項目的配置腳本,但是並不會執行其中的任務,只會評估任務的依賴性,根據其依賴性創建任務的有向無環圖。

Gradle引入了一個稱為隨需求變配置的特性,該特性使它能夠在構建過程中只配置相關和必要的項目。這在大型多項目構建中非常有用,因為它可以大大減少構建時間。

執行

在這個階段,Gradle 會識別在配置階段創建的任務的有向無環圖。並按照他們的依賴順序開始執行。
所有的構建工作都是在這個階段執行的。如編譯源碼,生成 .class 文件,復制文件等。

settings.gradle

這個文件是由 Gradle 約定命名的,默認名為 settings.gradle ,在初始化階段被執行。

對於多項目構建,必須在這里聲明要參與構建的所有項目。對於單項目構建就是可選的了,可有可無。

Gradle 是如何尋找 settings.gradle 的?

  1. 在當前目錄尋找
  2. 沒有找到的話就去父目錄尋找
  3. 仍然沒有找到就是是單項目構建了
  4. 如果找到了就是確定其中的項目,如果當前執行的項目在 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 的查詢地址

文檔參考


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM