Gradle 構建的一切都是基於兩個概念 :項目和任務; ...
構建語言
Gradle提供了一種領域特定語言,目前同時支持 Groovy 和 Kotlin 。
在 Groovy 構建腳本中(.gradle) 你可以使用任何 Groovy 元素。
在 Kotlin 構建腳本中 (.gradle.kts) 你可以使用任何 Kotlin 元素。
項目(Project) 和 任務(Task)
Gradle 構建的一切都是基於 兩個概念 :項目 和任務;
一個構建是由一個或多個項目組成的。項目的概念比較抽象,你可以創建一個 Project 用於生成一個 jar,也可以定義個項目用於生成 war 包,還可以定義一個項目用於發佈上傳你的 war等。
一個項目就是在你的業務範圍內,被你抽象出來的一個獨立的模塊,你可以根據工程的實際情況抽象歸類,最後這一個個的 項目組成了整個 Gradle 構建。
一個 項目又包含很多個任務,每個項目是由一個或多個任務組成的。任務就是一個操作,一個原子性的操作。比如打個 jar 包,複製一份文件,編譯一次 java 代碼等,這就是一個任務。
build.gradle & Project API
每個項目都有一個 build.gradle 文件,該文件是該項目的構建入口,可以在這這個文件里對該項目進行配置,比如配置版本,需要哪些插件,依賴哪些庫等。
我們通過配置這個文件描述我們的構建,這其實就是一個配置腳本。
每一個腳本在執行的時候都會被關聯到一個 Project 實例上。
在構建生命周期的初始化階段,Gradle 會為每個項目創建一個 Project 實例,並根據 build.gradle的內容配置這個實例。
也就是說每個 build.gradle 的配置都會被配置到 Project 實例上。
實際上,build.gradle 中幾乎所有的頂級屬性和代碼塊都是 Project 類的 API,
下麵通過訪問 Project.name 屬性驗證一下。
在 build.gradle
println "name is $name"
println "project.name is ${project.name}"
執行 build 任務,你將會得到下麵的輸出,輸出的值都是 項目的名字
第一條語句使用的是Project的頂級屬性。
第二條語句使用的 project 屬性 可以在腳本的任何地方訪問,它代表的是當前腳本的Project對象。
只有在你定義了和Project的成員(方法,屬性)同名的時候才需要使用 project ,其他時候直接使用 名稱即可訪問,例如第一條語句。
一個構建是由多個Project組成的,是通過項目樹的形式表示的。
可以在項目樹的根項目對所有的項目統一配置一些配置。例如,應用的插件,依賴的 Maven 中心庫等。
為所有子項目配置倉庫為 jcenter
subprojects{
repositories {
jcenter()
}
}
也可以為所有子項目配置 使用 Java 插件
subprojects{
apply plugin:'java'
repositories {
jcenter()
}
}
除了 subprojects 還有 allprojects ,從名字就可以看出來這不僅是對子項目的配置而是對所有項目的配置。
這兩個配置其實是兩個方法,接受一個閉包參數,對項目進行遍歷,遍歷的過程中調用我們自定義的閉包,所以我們可以在閉包里配置,列印,輸出或者修改 Project 的屬性。
Project 的屬性
Project 對象的屬性在 腳本全局都是可以使用的。
下麵列出一些常用的屬性,更全的屬性可以在 Project API 中查詢。
名字 | 類型 | 預設值 |
---|---|---|
project | Project | Project 實例 |
name | String | 項目名字 |
path | String | 項目的絕對路徑 |
description | String | 項目描述 |
projectDir | File | 配置腳本所在的目錄 |
buildDir | File | projectDir/build 輸出目錄 |
group | Object | 未指定 |
version | Object | 未指定 |
ant | AntBuilder | AntBuilder 實例 |
settings.gradle
這是一個設置文件,用於初始化以及項目樹的配置。設置文件的預設名字就是 settings.gradle,放在根項目目錄下。
關於構建生命周期和 settings.gradle 更詳細的可以看我的這篇文章
script API
當 Gradle 執行 Groovy 腳本(.gradle)時,會編譯腳本到實現了 Script 的類中。
也就是說,Script 介面中的所有屬性和方法都可以在腳本中使用。
當 Gradle 執行 Kotlin 腳本(.gradle.kts)時,會編譯腳本到 KotlinBuildScript的子類中。
也就是 KotlinBuildScript 類中的所有屬性和方法都可以在腳本中使用。
更詳細的可以參考 KotlinSettingsScript 和 KotlinInitScript 類,分別用於設置腳本和init腳本。
腳本即代碼
雖然我們在一個 Gradle 文件里寫腳本,但是我們寫的都是代碼,這一點一定要非常的清楚。
我們寫的確實是腳本,但不是簡單的腳本。在腳本里可以定義 Class ,內部類,導入包,定義方法、常量、介面等。
不要把它當作簡單的腳本,我們可以靈活的使用 Java ,Groovy ,Kotlin 和 Gradle.
例如 定義一個獲取當前日期的方法
def buildTime(){
def date = new Date()
def formattedDate = date.format('yyyyMMdd')
return formattedDate
}
# 變數 & 額外的自定義屬性
Gradle 支持兩種變數 :局部變數和自定義屬性
## 局部變數
局部變數使用 def 關鍵字聲明,局部變數只能在聲明的範圍內可見。
def myName = '佛系編碼'
額外的自定義屬性
Gradle 領域模型中 所有的對象 都可以添加額外的自定義屬性。
通過對象的 ext 屬性實現對自定義屬性的添加,訪問,設置值的操作。
添加之後可以通過 ext 屬性對自定義屬性讀取和設置,也可以同時添加多個自定義屬性。
//為 project 添加一個 age 屬性 並賦值 20
ext.age = 20
//為 project 添加兩個屬性
ext{
phone =110
address = '404'
}
task myTask {
//為 myTask 任務添加屬性
ext.myProperty = "myValue"
}
task extra{
doLast{
println "project : age= ${project.ext.age},phone= ${project.ext.phone} , address = ${project.ext.address}"
println "myTask : ${myTask.myProperty}"
}
}
# 創建一個任務
task hello {
doLast {
println 'Hello world!'
}
}
這裡的 task 看著像一個關鍵字,實際上是一個方法,這個方法的原型是 TaskContainer.create()
任務的創建就是使用這個方法給 Project 添加一個 Task 類型的屬性;所以才能使用任務名字引用一些API,例如為任務添加額外的屬性。
# 任務依賴和任務排序
一個任務可以依賴其他任務或者在其他任務執行後再執行。
Gradle 確保在執行任務時遵守所有任務依賴性和排序規則,以便在所有依賴項和任何 “必須運行” 的任務執行之後再執行任務。
Gradle 為我們提供了幾個方法用來控制任務的依賴和排序,就是下麵這幾個
- Task.dependsOn(java.lang.Object[])
- Task.setDependsOn(java.lang.Iterable)
- Task.mustRunAfter(java.lang.Object[])
- Task.setMustRunAfter(java.lang.Iterable)
- Task.shouldRunAfter(java.lang.Object[])
- Task.setShouldRunAfter(java.lang.Iterable)
這些方法可以接收 任務,任務名字,路徑等,具體參數可以在 Task文檔 里查看
task hello {
doLast {
println 'Hello world!'
}
}
task taskX {
dependsOn hello
doLast{
println "I'm $name."
}
}
task taskY {
doFirst {
println "I'm $name."
}
}
如果 taskX 要依賴 taskY 的話,並不能直接引用,因為 taskY 是在 taskX 之後定義的。
task taskX {
dependsOn 'taskY'
doLast{
println "I'm $name."
}
}
預設任務
在沒有指定執行任務的時候,可以在腳本中定義預設任務,使用 defaultTasks 方法
這個方法接收 字元串參數,傳入任務的名稱即可·
defaultTasks 'hello','taskY'
外部依賴
用添加外部依賴,必須添加依賴所在倉庫。例如 jcenter,maven,google等
目前支持很多類型的倉庫,基本上都在這裡列出來,可以查看 倉庫類型
添加 google 倉庫
allprojects {
repositories {
mavenCentral()
google()
jcenter()
}
}
在 Android 的項目中,這都是放在根項目里的 allprojects 方法里,對所有項目統一配置
添加外部依賴
dependencies {
implementation 'io.reactivex.rxjava2:rxjava:2.1.2'
}
在 Android 中依賴的添加放在了各個module 中,按需添加,哪個模塊需要在哪個模塊的構建腳本里添加。
依賴屬性分為三部分
- group: 這個屬性用來標識一個組織、公司或者項目,可以用點號分隔,例如上面的 io.reactivex.rxjava2
- name: name屬性唯一的描述了這個依賴,例如上面的 rxjava
- version: 一個庫可以有很多個版本。例如上面的 2.1.2
其中 implementation 為配置項,配置也有很多種類型,下麵貼出來一張來自 Google 的說明:詳情可以查看這個 依賴項配置
最後是 DSL 的API 地址 https://docs.gradle.org/current/dsl/index.html