本篇文章已授權微信公眾號 dasu_Android(大蘇)獨家發(fā)布
最近看了一本書《Android Gradle 權威指南》,對于 Gradle 理解又更深了分飞,但不想過段時間就又忘光了千康,所以打算寫一篇讀書筆記享幽,將書中一些我個人覺得蠻有用的點記錄、總結一下拾弃。
前言
首先,先來過一下整書的目錄章節(jié)摆霉,先大概清楚整本書都介紹了哪些知識點:
第 1 章 Gradle 入門
第 2 章 Groovy 基礎
第 3 章 Gradle 構建腳本基礎
第 4 章 Gradle 任務
第 5 章 Gradle 插件
第 6 章 Java Gradle 插件
第 7 章 Android Gradle 插件
第 8 章 自定義 Android Gradle 工程
第 9 章 Android Gradle 高級自定義
第 10 章 Android Gradle 多項目構建
第 11 章 Android Gradle 多渠道構建
第 12 章 Android Gradle 測試
第 13 章 Android Gradle NDK 支持
第 14 章 Android Gradle 持續(xù)集成
整本書介紹的內容很全豪椿,從 Gradle 的環(huán)境配置 --> Groovy 介紹 --> 講解項目中常見 gradle 文件作用 (setting.gradle, build.gradle) --> 詳細講解 build.gradle 文件內每行代碼的含義 --> 各種高級自定義使用。
看完這本書携栋,對于掌握項目中的 build.gradle 文件應該就不成問題了搭盾,雖然將整本書過了一遍,但其實我也只是著重挑了一些自己感興趣的章節(jié)深入閱讀婉支,所以就來記錄一下鸯隅,方便后續(xù)查閱吧。
筆記
1. Groovy 基礎
首先清楚一點向挖,Gradle 是基于 Groovy 語言的蝌以,他們之間的關系就像《Android 群英傳:神兵利器》中說的:
Groovy 對于 Gradle,就好比 Java 對于 Android
所以何之,了解一些 Groovy跟畅,對于學習 Gradle 來說,肯定是有所幫助的溶推。
關于這方面內容徊件,我之前寫過一篇博客:學點Groovy來理解build.gradle代碼
所以,這里不會再去介紹蒜危,但有幾個點可以提一下虱痕,如果你都還不怎么熟悉,那么可以點開鏈接去看看:
- Groovy 中支持用
'xxx'
,"xxx"
,'''xxx'''
,/xxx/
等多種方式來定義字符串辐赞,所以如果在 build.gradle 里看到既有單引號又有雙引號定義的字符串時部翘,不用去疑惑他們到底是不是字符串。 - Groovy 中的方法支持省略括號占拍,也就是說略就,在 build.gradle 中一行行的代碼捎迫,大部分都是在調用某個方法。
- Groovy 中有一種特性叫閉包表牢,說白點也就是代碼塊窄绒,支持作為方法參數(shù),結合方法括號省略的特點崔兴,在 build.gradle 里 defauleConfig {} 代碼塊之類的其實也都是在調用一個個方法彰导。
2. Android 項目中的 Gradle
新建一個項目時,Android Studio 會自動生成項目的初步結構敲茄,這通常會攜帶一些 gradle 相關的文件位谋,這一節(jié)就來學學,各個 gradle 文件都有什么作用
2.1 gradle/wrapper 目錄
就像我們要開發(fā) Java 程序堰燎,本地需要配置 JDK 環(huán)境掏父,要開發(fā) Android 程序,需要配置 SDK 一樣秆剪,想要借助 Gradle 來構建項目赊淑,那么按理說本地也需要配置相關的 Gradle 環(huán)境才對。
而我們之所以可以省掉這一步仅讽,就是 gradle/wrapper 這個目錄下的文件的作用了陶缺,可以先看看 gradle-wrapper.properties 這個文件的內容:
#Thu May 24 10:30:42 CST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
內容無非就是一些配置項,而最重要的就是最后一句洁灵,指明了當前這個項目要使用哪個版本的 Gradle 來構建饱岸,我們在 Android Studio 的 File -> Project Structure -> Project 里配置的 Gradle Version,最終改變的其實就是上述文件里最后一行的 Gradle 版本屬性值
官方說了徽千,提供了 gradle/wrapper 這種方式苫费,可以讓你特別靈活的進行配置,想換個 Gradle 版本來構建項目罐栈,只需要修改這個配置文件的 Gradle 版本屬性值即可黍衙,當然也可以直接通過 AS 提供的 UI 界面操作,結果都一樣荠诬。
由于 Gradle 更新?lián)Q代特別快琅翻,而且新的大版本經常都會提供很多新特性,這就導致了在 clone Github 上一些開源項目到本地構建時經常有報錯的問題柑贞,本質原因就是因為它使用的 Gradle 版本跟你本地不一樣方椎,而由于有堵巨墻的原因,導致一直沒法成功下載它配置的 Gradle 版本钧嘶,進而就無法構建項目棠众,而報錯了。
網(wǎng)上說的一些解決方案是讓你手動去修改 gradle-wrapper.properties 文件里的 Gradle 版本,改成你本地的版本闸拿,但我覺得這種方法不一定適用空盼,這取決于那個項目中是否有用到一些新特性,以及你本地的 Gradle 版本是否兼容項目中用到的 Gradle 新特性新荤。
通常來說揽趾,如果你本地的 Gradle 比克隆的項目的 Gradle 版本高的話,那么這種直接修改項目的 Gradle 版本方式應該是可行的苛骨,那么怎么知道你本地都有哪些 Gradle 版本呢:
默認在 C 盤篱瞎, C:\Users\suxq\ .gradle 目錄下有 Android Studio 自動幫你下載的 Gradle 的各個版本,只要你在 gradle-wrapper.properties 修改了 Gradle 的版本號痒芝,那么當你在構建項目時俐筋,就會先到你電腦的這個路徑下查找相對應版本的 Gradle,如果可用严衬,則直接進行構建項目任務澄者,如果不存在,那么就會自動去下載對應版本的 Gradle瞳步。
最后闷哆,還有個問題,怎么確定都有哪些 Gradle 版本可用呢单起?如果想要自己去下載,不借助 Android Studio 可行么劣坊?
當然可以嘀倒,去官網(wǎng)找到對應版本點擊下載即可:http://services.gradle.org/distributions/
下載完成之后,將文件放到上面介紹的 C 盤下的 .gradle 文件里相對應版本的目錄下即可局冰。
如果你有自己去嘗試下載测蘑,你就會體驗到,下載速度是有多么的龜速康二,90M 左右的文件硬是要下載個把小時碳胳。同樣的道理,你自己下載這么慢沫勿,那通過 Android Studio 下載的速度也同樣這么慢挨约,兩者唯一的區(qū)別就只是在于你自己下載時你可以看到速度和進度。
這樣一來的話产雹,明白為什么有時候打開新項目或者打開 Github 上的項目時诫惭,Android Studio 會一直卡在構建中的原因了吧?
因為這個項目用到了你本地沒有的 Gradle 版本蔓挖,所以 Android Studio 自動去下載了夕土,但由于都懂的原因,下載速度賊慢瘟判,因此網(wǎng)上才有一些博客教你說讓你要去翻墻怨绣,明白為什么了吧角溃。
另外,網(wǎng)上還有一些博客會讓你不管它篮撑,讓你等隔天再去打開這個項目减细,然后有時候你會發(fā)現(xiàn),隔天打開竟然能正常構建項目了咽扇,莫名其妙的就好了邪财,就不一直卡在構建中了。這是由于 Android Studio 會有一個后臺構建的功能质欲,也就是說它可以在背后默默的幫你自動去下載 Gradle树埠,雖然速度賊慢,但總有下載完成的時候嘶伟,當你隔天再去打開這個新項目時怎憋,如果已經下載好了,那自然就可以正常構建使用了九昧。
2.2 gradlew.bat 文件
gradlew 文件和 gradlew.bat 文件绊袋,兩份沒有什么差別,它們都是腳本文件铸鹰,區(qū)別只是一個是 shell 腳本癌别,一個是批處理腳本,那么自然一個是用來在 Linux 上運行蹋笼,一個在 Windows 上運行展姐。
感興趣的可以去看看這份腳本代碼,其中比較關鍵的代碼:
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
大概翻譯一下剖毯,它借助了 gradle/wrapper 目錄下的 gradle-wrapper.jar 文件圾笨,并借助了 java 命令或衡,提供了可讓我們直接以命令行形式運行一些相應的 gradle 指令苦始,而這些指令在 gradle-wrapper.jar 文件中都提供了相應的實現(xiàn)。
比如: gradlew -version
直接在 Android Studio 的 Terminal 面板運行 gradlew -version
命令萤悴,或者在 Dos 窗口胶滋,進到項目的根目錄下執(zhí)行該命令板鬓,都可以,前者只是打開時就默認將項目根目錄作為當前路徑了镀钓。
這也是為什么一些資料說穗熬,如果沒有配置 Gradle 環(huán)境,那么在每個項目根目錄下也可以運行 gradle 命令的原因丁溅,因為每個項目都提供了 gradlew.bat 腳本以及 gradle/wrapper 目錄下的 gradle-wrapper.jar 文件支持唤蔗。你可以試一下,刪掉兩者中任意一個,就沒法正常運行 gradle 命令了妓柜。
那么箱季,提供了腳本文件來支持直接運行 gradle 命令有什么用呢?
用處可多了棍掐,我們在構建項目時藏雏,基本都是直接借助 Android Studio 的圖形界面來操作,點一點就可以了作煌。但有時候掘殴,經常會遇見一些構建失敗的情況,然后日志中經常會給我們這么一段提示:
如果想查看更多的日志信息粟誓,需要在執(zhí)行命令的時候加上一些參數(shù)奏寨,而這種時候就需要通過命令行的形式來了,那么這時腳本文件也就派上用場了:
這樣一來就可以看到更多的日志信息了鹰服,當然我舉的這個例子不好病瞳,因為可以直接看出問題出在哪了,不需要再去獲取更多的輔助信息來定位了悲酷。
但有些時候套菜,Gradle 構建時確實就是失敗了,然后給的信息又少设易,讓人莫名其妙逗柴,不知道為啥失敗了,這種時候就可以借助命令行形式來執(zhí)行這個 task顿肺,然后添加一些參數(shù)來獲取更多的輔助日志嚎于。至于要添加哪些參數(shù),執(zhí)行什么命令挟冠,通常情況下,Gradle 構建失敗時都會給出建議袍睡,跟著來就可以了知染。
2.3 setting.gradle 文件
setting.gradle 文件通常是當項目涉及到多 Module 的場景。
只有在 setting.gradle 中 include 的 Module斑胜,才會被加入構建中控淡,也就是說,如果一個項目文件夾內止潘,包含了很多子工程掺炭,但如果沒在 setting.gradle 中將這些子工程 include 進來的話, 這些 Module 是不會參與進構建的凭戴。
另外涧狮,如果子工程的這些 Module 都直接放在了項目根目錄中,那么 setting.gradle 中只需要寫 include 就可以了,那如果這些子工程是放在別的地方者冤,那么也可以通過修改 project().projectDir 來指定子工程的具體路徑肤视,也就是說,所有的 Module 并不一定需要全部集中放在同一個項目內涉枫。
2.4 build.gradle 文件
一個項目中可能存在多個子工程邢滑,每個子工程構建都應該是相互獨立的,也就是說愿汰,每個子工程都可以根據(jù)自己的需要困后,配置各種依賴,插件等衬廷。那么摇予,Gradle 是如何分開來管理每個子工程的構建任務的呢?
這就是 build.gradle 文件的作用了泵督,所以你會發(fā)現(xiàn)趾盐,每個子工程,也就是每個 Module 都會有一個 build.gradle 文件小腊,Gradle 就是以這個文件為根據(jù)來構建這個 Module救鲤。
那么,如果有些配置項秩冈,在所有的子工程中都是一致的話本缠,如果在每個子工程里都去重復粘貼的話,當這個共同的配置項需要發(fā)生變化時入问,維護起來會非常麻煩丹锹,這也就是為什么根目錄下面還會有一個 build.gradle 文件。
根目錄下的這個 build.gradle 是統(tǒng)籌全局的芬失,在這里楣黍,你可以配置一些所有工程共同的配置項,比如 Android Gradle 的版本棱烂,依賴庫的倉庫地址這些所有工程的共同配置項租漂。
也就是說,其實將根目錄下的 build.gradle 文件里的內容移到每一個工程下的 build.gradle 里颊糜,也是可行的哩治。但沒必要這樣做,吃飽了撐著衬鱼。
3. Gradle 基礎
3.1 task 概念
task 是 Gradle 中的一種概念业筏,引用書中的解釋:
一個 task 其實就是一個操作,一個原子性的操作鸟赫,比如打個 jar 包蒜胖,復制一份文件消别,編譯一次 Java 代碼,上傳一個 jar 到 Maven 中心庫等翠勉,這就是一個 Task妖啥,和 Ant 里的 Target, Maven 中的 goal 是一樣的对碌。
有點類似于 Java 里面的類荆虱,但又有很多不同之處。我們要通過 Java 命令來執(zhí)行某個 java 文件朽们,那么至少需要一個類怀读,類里面需要有 main 方法,這個 java 文件才能運行起來骑脱。
同樣菜枷,要通過 gradle 命令來執(zhí)行某個構建任務,那么至少需要一個 task叁丧,這個構建任務才能跑起來啤誊。
但更多的是不同的概念,多個類之間可以有相互依賴的關系拥娄,類中持有另一個類的引用等等蚊锹。
但在 task 方面,多個 task 之間只能有前后依賴關系稚瘾,即某個 task 的運行是否需要哪個 task 先運行的基礎上才允許牡昆,也就是說,在 Gradle 的構建工作過程中摊欠,多個 task 是構成一條直線的丢烘,一個個 task 按順序的去工作,而不存在某個 task 工作到一半時去調用另一個 task些椒。
不過播瞳,通常情況下,我們并不需要去接觸到 task 層面免糕,build.gradle 文件里的代碼大多都只是在調用各種方法進行各種配置狐史,而最后,會根據(jù)這份文件生成很多 task说墨,比如:
在 Android Studio 右側的 Gradle 的面板這邊,就是一個個的 task苍柏,assemble 是一個 task尼斧,build 也是一個 task,很多 task 是 Gradle 已經提供的试吁,而有些 task 則是根據(jù) build.gradle 里面的配置項自動生成的棺棵,比如 assembleDebug 這一類楼咳。
要執(zhí)行 task 的方式,可以通過 AS 的圖形界面點一點即可烛恤,也可以通過命令行方式母怜,由于根目錄提供了 gradlew 腳本文件,因此可以在根目錄下執(zhí)行 gradlew task名
即可缚柏。
3.2 gradle 插件概念
Gradle 是用來構建項目的苹熏,但并不是說只能用于構建 Android 的項目,Java 的也行币喧,C++ 的也行轨域,很多很多。
那如果我只是做 Android 開發(fā)杀餐,我也就只需要 Gradle 構建 Android 項目的功能即可干发,其他的又不需要,鑒于此史翘,Gradle 封裝好了基本的構建工作枉长,然后提供了插件的接口,支持根據(jù)各自需要去擴展相應的構建任務琼讽。
以上就是我對于 Gradle 插件概念的理解必峰,我認為它是用于給大伙可以根據(jù)需要自行去擴展。
就拿 Android 項目來說跨琳,來看一份 build.gradle 文件結構:
apply plugin: 'com.android.application'
android {
...
defaultConfig {
....
}
}
dependencies {
...
}
如果有點擊方法進去看過源碼的話自点,你會發(fā)現(xiàn):
發(fā)現(xiàn)沒有,dependencies 是 Gradle 提供的方法脉让,但 android桂敛,defaultConfig 卻都是 Android Gradle 插件提供的方法了。
也就是說溅潜,其實 Gradle 只提供了構建項目的一些基本功能术唬,如配置依賴庫,不管什么項目都需要滚澜。但像 android {} 代碼塊里的配置項粗仓,很明顯,就只有 Android 項目才需要用到了设捐,所以這些配置并不是由 Gradle 來提供的借浊,而是由 Android Gradle 插件提供的,這也就是為什么在根目錄的 build.gradle 文件里會有這么一行代碼:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
}
}
com.android.tools.build:gradle:2.3.3
這行代碼其實就是聲明了我們的項目還需要使用 Android Gradle 插件萝招,版本號為 2.3.3蚂斤,而插件的下載地址在 jecnter() 倉庫。
所以槐沼,得搞清楚曙蒸,Gradle 和 Android Gradle 是兩種概念捌治,也是兩個不同的東西,如果有人問說你項目構建的 Gradle 的版本是多少纽窟,得搞清楚肖油,他想問的是 Gradle,還是 Android Gradle 插件臂港。
但是我們在根目錄的 build.gradle 里是可以配置多個插件的森枪,比如如果有使用 GreenDao,或者使用了 Jcenter 的上傳功能:
buildscript {
repositories {
jcenter()
}
dependencies {
//Google提供的構建Android項目的插件
classpath 'com.android.tools.build:gradle:2.3.3'
//GreenDao 提供的插件
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
//Jcenter提供的插件
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.4'
//Maven提供的插件
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.4.1'
}
}
那么趋艘,Gradle 在根據(jù) build.gradle 構建 Module 時疲恢,怎么知道要使用哪個插件呢,聲明了這么多瓷胧。
這就是為什么在每個 Module 的 build.gradle 文件的開頭有行 apply plugin
的代碼了显拳。
apply 是 Gradle 的方法,它可以接收一個 map 類型的參數(shù)搓萧,而在 Groovy 中杂数,map 的定義可以直接 'key': value
,也就是說:
apply plugin: 'com.android.application'
//等效于
// def map = ['plugin':'com.android.application']
// apply(map)
每個 build.gradle 開頭這行代碼瘸洛,其實是調用了 Gradle 的 apply() 方法揍移,然后傳入了一個 map 值,key 為 plugin反肋, value 為 ‘com.android.application'那伐,那么 Gradle 就知道了你這個項目需要使用到一個 id 為 'com.android.application' 的插件來輔助構建了,那么它就會去你在根目錄下配置的插件列表里尋找石蔗。
也就是說罕邀,apply plugin 是 Gradle 規(guī)定并提供的,但 'com.android.application' 則是由 Android Gradle 來提供的养距。
那么诉探,小結一下,要使用一個 Gradle 插件的話棍厌,先得在根目錄下聲明你要用的插件以及版本肾胯,當然也得指定插件的下載地址,然后在你具體的 Module 的 build.gradle 的開頭通過 apply plugin 方式來應用插件耘纱,這個插件得有一個唯一區(qū)分開的 id 值敬肚。
4. 區(qū)分 Gradle 和 Android Gradle
先來看張圖,這個在 File -> Project Structure -> Project 打開束析,在這里可以配置 Gradle 和 Android Gradle 插件的版本帘皿。
最開始接觸的時候,我看到這里是有些迷茫的畸陡,怎么有一個 Gradle 版本鹰溜,又有一個 Android Gradle 版本。當別人問我你 Android Studio 使用的 Gradle 版本是多少時丁恭,我也傻乎乎的打開根目錄下的 build.gradle 文件里曹动,看到 com.android.tools.build:gradle:2.3.3
,然后跟他說 2.3.3 版本牲览,當初根本沒搞清楚這兩個有什么區(qū)別墓陈,一直以為是同一個東西。
所以第献,要搞清楚 Android Gradle 其實只是 Gradle 的一個插件贡必,是 Google 基于 Gradle 提供的插件接口所做的一些擴展。
所以庸毫,要查找 Android Gradle 的相關資料仔拟,自然就不是去 Gradle 官網(wǎng)了,而是要去 Android 官網(wǎng)找:
https://developer.android.google.cn/studio/releases/gradle-plugin
由于 Gradle 更新?lián)Q代很快飒赃,又經常提供一些新特性利花,所以 Android Gradle 插件也就跟隨著發(fā)布了很多版本,所以载佳,Android Gradle 的版本并不是可以任意更改的炒事,因為它是基于每一個 Gradle 版本開發(fā)的,因此需要在對應的 Gradle 版本中才能使用蔫慧。
這也是為什么挠乳,我們有時候直接修改根目錄下的 build.gradle 中的 Android Gradle 版本時,會報一些錯誤說需要 Gradle 版本在多少在可以使用的原因姑躲,至于這些對應關系睡扬,官網(wǎng)當然有給出來了:
舉個例子,如果你 Gradle 版本使用的是 3.3肋联,然后你在 Github 上 clone 了某個人的項目威蕉,他的項目中使用的 4.4 的 Gradle 版本 和 3.1.0 的 Android Gradle 插件,但是你發(fā)現(xiàn)在打開這個項目的時一直處于構建中橄仍,一直打不開韧涨。
你查了下原因,網(wǎng)上有教程說侮繁,讓你將項目中的 gradle/wrapper 文件里的 Gradle 版本換成你本地項目中的 Gradle 版本虑粥,還跟你說因為它使用的版本你本地沒有,而且被墻了宪哩,你下載需要很長時間娩贷,讓你直接改成使用你本地的版本即可。
你改了后锁孟,發(fā)現(xiàn)彬祖,是可以打開項目了茁瘦,但構建的時候又報錯了,說你使用了 3.1.0 的 Android Gradle 插件储笑,需要讓你將 Gradle 版本改成 4.4 才可以正常構建甜熔,這 MMP 不是又繞回去了。
所以說突倍,別聽他放屁腔稀,搞清楚了 Gradle 和 Android Gradle 插件的關系之后。那為什么會一直在構建中羽历,為什么會報錯我們心里就有數(shù)了焊虏,要解決,沒有其他辦法秕磷,就是要將對應的版本下載下來诵闭。
所以,你應該去搜的是如何下載跳夭,Android Gradle 插件并沒有被墻涂圆,如果想自行下載,可以參考我之前的博客: 如何用Android Studio查看build.gradle源碼币叹,而至于 Gradle 要如何下載润歉,如果官網(wǎng)下載不了,那就去搜搜有沒有相關的鏡像吧颈抚。
本篇就先到這里了踩衩,還會有一篇下篇,下篇的內容就是側重于介紹 build.gradle 里各種配置項的作用和意義了贩汉,還有就是如何自己寫 Gradle 腳本來運行驱富,敬請期待~
最近(2018-03)剛開通了公眾號,想激勵自己堅持寫作下去匹舞,初期主要分享原創(chuàng)的Android或Android-Tv方面的小知識褐鸥,準備可能還有點不足,感興趣的可以先點一波關注赐稽,謝謝支持~~