Gradle系列之構建腳本基礎

原文發於微信公眾號 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),一起交流學習。