Gradle系列之構建指令碼基礎

躬行之發表於2020-07-13

原文發於微信公眾號 jzman-blog,歡迎關注交流。

前面兩篇文章分別介紹了 Gradle 基礎知識以及 Groovy 相關基礎知識,這也是學習 Gradle 所必需瞭解的,文章連結如下::

本文將對 Gradle 整體進行了介紹和學習,瞭解了 Task、Project 等相關概念以及對使用 Gradle 來構建專案的一些常用操作,主要內容如下:

  1. Setting 檔案
  2. Build 檔案
  3. Project 和 Tasks
  4. 任務的建立
  5. 任務依賴
  6. 任務間的互動
  7. 自定義屬性
  8. 總結

Setting 檔案

說一下 Gradle 構建專案的 Setting 檔案,該檔案主要用來配置當前工程,比如 Android 開發中一個專案中可能有多個子 Module,當不需要某個子 Module 時,可以取消該 Module 在配置檔案 Setting 中的配置即可,當然只有在 Setting 檔案中配置的子 Module 才會被構建,當然不只是 Android 開發,只要使用 Gradle 構建的專案都一樣,Setting 是 Gradle 構建專案預設的配置檔名,下面簡單測試一下 Setting.gradle 檔案的使用,測試工程目錄如下:

├─GradleSetting
│  ├─.gradle
│  │  ├─4.1
│  │  │  ├─fileChanges
│  │  │  ├─fileHashes
│  │  │  └─taskHistory
│  │  └─buildOutputCleanup
│  └─test
│      └─Method
│          └─.gradle
│              ├─4.1
│              │  ├─fileChanges
│              │  ├─fileHashes
│              │  └─taskHistory
│              └─buildOutputCleanup
│ build.gradle
│ setting.gradle

在工程名為 GradleSetting 的工程中 test 資料夾下有一個 Method 的子專案,這裡會通過配置 setting.gradle 檔案將子專案 Method 構建到 GradleSetting 中,setting.gradle 檔案內容如下:

println "---------test----Setting.gradle----------"
//輸出當前工程目錄
println(rootDir)
//指定要參與構建的子專案
include ':Method'
project(':Method').projectDir = new File(rootDir,'test/Method')

來看一下輸出結果:

PS E:\Gradle\study\GradleSetting> gradle testGradleSetting
---------test----Setting.gradle----------
E:\Gradle\study\GradleSetting

> Configure project :
testGradleSetting

> Configure project :Method
3
3
30
獲取方法返回的結果:30
1
2
3
4
5


BUILD SUCCESSFUL in 2s

因為在 setting.gradle 檔案中配置了 Method,從輸出結果看 Method 確實參與了構建,取消在 setting.gradle 檔案中的配置,則不會構建 Method,最好自己驗證一下。

上面配置了子專案 Method 所在的位置,如果不指定則預設是與 setting.gradle 同級的目錄。

Build 檔案

如果選擇使用 Gradle 構建專案,則每個專案都有一個 build.gradle 檔案,該檔案是專案構建的入口,對整個專案的配置生效,可以在根專案配置子專案的一下通用配置,比如配置子專案的倉庫為 jcenter,這樣子專案中所有的依賴就指向 jcenter 中心庫下載,下面是參考程式碼:

//配置子專案依賴的倉庫
subprojects{
	repositories{
		jcenter()
	}
}

//配置全部專案
allprojects{
	
}

...

通過本小節主要了解 build.gradle 檔案的作用即可,實際開發中針對不同型別的專案會有更詳細的相應配置策略。

Project 和 Tasks

在 Gradle 中有很多 Project,可將某個 Project 打包成 jar 提供給另一個 Project 使用,每個 Project 都是根據其業務需求抽象出來的一個子模組,最終通過 Gradle 構建成完整的專案。

每個 Project 允許有多個 task,Task 理解為任務,task 主要 完成某個具體的功能點,比如 wrapper task 主要就是完成 wrapper 檔案的建立。

任務的建立

對於任務的建立已經比較熟悉了,下面使用 task 宣告一個任務:

//1. 建立一個任務
task createTask{
	doFirst{
		println 'doFirst'
	}

	doLast{
		println 'doLast'
	}
}

//2. 使用TaskContainer建立一個任務,Project已經定義的TaskContainer,即tasks
tasks.create("createTask1"){
	doFirst{
		println 'doFirst'
	}

	doLast{
		println 'doLast'
	}
}

task 可以理解為建立任務的關鍵字,實際上 task 是 Project 裡面的一個方法,在 Groovy 中可以省略方法引數上的括號,花括號裡的內容是一個閉包,主要是對 task 進行相關配置,doFirst 和 doLast 是 Task 中常用的兩個方法,分別會在該 task 開始和結束時執行。

任務依賴

任務之間可以相互依賴,可以控制某個任務執行的先後順序,比如在執行 A 之前必須先執行 B,此時任務 A 依賴任務 B,具體參考如下程式碼:

//單任務依賴:通過dependsOn指定要依賴的任務
task B(dependsOn: A){
	doFirst{
		println 'B'
	}
}

task C{
	doFirst{
		println 'C'
	}
}

//多工依賴
task D{
	dependsOn A, C
	doFirst{
		println 'D'
	}
}

下面看一下執行多依賴任務 gradle D 的執行結果:

PS E:\Gradle\study\GradleSetting> gradle D

> Task :A
A

> Task :C
C

> Task :D
D

BUILD SUCCESSFUL in 2s

顯然,執行任務 D,其依賴的其他兩個任務先執行,控制了任務執行的先後順序。

注意:指令碼是按照順序執行,如果任務任務 A 和 C 在任務 D 的後面定義,當執行任務 D 的時候肯定會出錯。

任務間的互動

建立的任務都有自己的名稱,其型別是 Task,那麼我們就可以通過 Task API 來控制控制任務的執行,使用任務名操作任務的原理是:Project 在建立任務的時候,已經將該任務對應的任務宣告為 Project 物件的一個型別為 Task 的一個屬性,測試程式碼如下:

//任務之間的互動
task E{
	println 'hello e'
	println "E是不是Project的屬性:"+project.hasProperty('E')
}

E.doFirst{
	println 'doFirst'
}

E.doLast{
	println 'doLast'
}

上述程式碼的執行結果如下:

PS E:\Gradle\study\GradleSetting> gradle E

> Configure project :
hello e
E是不是Project的屬性:true

> Task :E
doFirst
doLast


BUILD SUCCESSFUL in 1s

自定義屬性

Project 和 Task 都允許使用者新增額外的自定義屬性,通過應用所屬對應的 ext 屬性來實現,新增之後可以通過 ext 屬性對自定義的屬性進行讀取和設定,如果要同時新增多個自定義屬性,可以通過 ext 程式碼塊,參考如下程式碼定義自定義屬性:

apply plugin:"java"

//自定義單個屬性
ext.name1 = "Gradle"
//自定義多個屬性
ext{
	age = 10
	score = 100
}

//在SourceSet中使用自定義屬性
sourceSets.all{
	ext.resourceDir = null
}

//配置自定義屬性
sourceSets{
	main{
		resourceDir = "main/res"
	}
	test{
		resourceDir = "test/res"
	}
}

task customProperty{
	println "name=${name1}"
	println "age=${age}"
	println "score=${score}"

	sourceSets.each {
		println "${it.name} resourceDir is ${it.resourceDir}"
	}
}

上述程式碼的執行結果:

PS E:\Gradle\study\GradleSetting> gradle customProperty

> Configure project :

name=Gradle
age=10
score=100
main resourceDir is main/res
test resourceDir is test/res

BUILD SUCCESSFUL in 2s

自定義屬性相較區域性變數作用域更加廣泛,可以跨 Task、Project 訪問自定義屬性,只要能訪問這些屬性所屬的物件,那麼這些屬性就可以被訪問到, Android 開發中可以使用自定義屬性單獨定義版本號、版本名稱以及用到的第三方庫的版本,將其同意在單獨的 gradle 檔案中,各 Module 直接獲取即可,不僅方便管理依賴庫的版本,還在一定程度上提高工作效率。

總結

Gradle 指令碼基於 Grooy ,而 Groovy 完全相容 Java 語法,Gradle 指令碼本質上還是程式碼,在 Gradle 中可以利用相關語法來完成相關功能。可以關注公眾號:躬行之(jzman-blog),一起交流學習。

相關文章