系列目錄
1.【Gradle深入淺出】——初識(shí)Gradle
2.【Gradle深入淺出】——Gradle基礎(chǔ)概念
3.【Gradle深入淺出】——Android Gradle Plugin 基礎(chǔ)概念
4.【Gradle深入淺出】——Gradle配置(一)
5.【Gradle深入淺出】——Gralde配置(二)
一瓷翻、為什么要寫Gradle
Gradle其實(shí)是自己一直想要了解的東西堪簿,但是一直沒有下定決心晶渠,因?yàn)檫@個(gè)東西袍祖,你要說很有用,平時(shí)常用的可能就是那幾個(gè)配置椒楣,要說沒用贡歧,每次到關(guān)鍵的時(shí)候,gradle總會(huì)是你對(duì)于Android整體學(xué)習(xí)的一個(gè)攔路虎角溃。為什么這樣說呢,縱觀現(xiàn)在Android整體的學(xué)習(xí)路線篮撑,其實(shí)歸納總結(jié)可以分為三個(gè)部分减细。
- 1.Android基礎(chǔ)路線
也就是我們常說的業(yè)務(wù)開發(fā),對(duì)于組件赢笨,MVP,MVVM的使用 - 2.Android運(yùn)行時(shí)路線
也就是我們平時(shí)說的反射未蝌,hook等黑科技驮吱,而這類黑科技往往是在運(yùn)行時(shí)對(duì)于系統(tǒng)層面或者源碼層面的動(dòng)態(tài)調(diào)整,達(dá)到我們的目的树埠。 - 3.編譯期路線
其實(shí)運(yùn)行時(shí)做的調(diào)整已經(jīng)能夠完成我們所有的需求糠馆,但運(yùn)行時(shí)對(duì)于性能的影響還有穩(wěn)定性一直被人詬病嘶伟,所以現(xiàn)在逐漸發(fā)展成編譯期路線怎憋,也就是在編譯期做處理,將我們想做的入侵編譯期九昧,最終打到我們的apk包中绊袋,達(dá)到我們想要的效果,而由于是在編譯期做的處理铸鹰,所以是前置處理好的癌别,也就沒有了運(yùn)行時(shí)效率的問題。常見的比如組件化蹋笼,插樁熱修復(fù)展姐,Router,AOP剖毯,包體積優(yōu)化圾笨。
我們其實(shí)可以發(fā)現(xiàn),一個(gè)技術(shù)無非就兩種逊谋,運(yùn)行時(shí)/編譯期擂达,從上面的介紹就會(huì)發(fā)現(xiàn),同一個(gè)技術(shù)胶滋,編譯期和運(yùn)行時(shí)就有不同的解決方案板鬓,比如ARouter早期是用運(yùn)行時(shí)反射查找,后面變成編譯期生成映射關(guān)系的類究恤,再比如熱修復(fù)有hook的函數(shù)替換俭令,也有插樁的方式。而且由于現(xiàn)在Android生態(tài)越來越重視性能問題部宿,現(xiàn)在越來越多的庫唤蔗,開始遷移到編譯期,所以可以看出現(xiàn)在對(duì)于編譯的學(xué)習(xí)對(duì)于Android的進(jìn)階開發(fā)是非常重要的窟赏。
那么既然提到Android的編譯妓柜,就肯定脫離不了Gradle的學(xué)習(xí),這里就不展開Android從ADT到Gradle的變化歷程涯穷,但是Gradle的強(qiáng)大棍掐,讓不僅僅是Android,后端的Java項(xiàng)目也開始使用Gradle來進(jìn)行打包拷况,在了解了Gradle后作煌,才能讓我們進(jìn)一步學(xué)習(xí)Android的各項(xiàng)技術(shù)掘殴,可以說這個(gè)已經(jīng)成為一個(gè)攔路虎,或者說基石粟誓。
以上是我自己的想法奏寨,也是我自己對(duì)于Android學(xué)習(xí)的一個(gè)理解,所以我想開展一個(gè)長(zhǎng)篇的Gradle學(xué)習(xí)系列鹰服,爭(zhēng)取能較為全面深入的學(xué)習(xí)Gradle病瞳。
二、Gradle是什么
以上的內(nèi)容可能來源于其他的一些博客的片段中悲酷,以為偏概念的東西套菜,沒辦法做到純?cè)瓌?chuàng)編寫,所以我做的是精選我認(rèn)為值得學(xué)習(xí)的內(nèi)容设易。
首先我們看下Gradle官網(wǎng)對(duì)于他自己的介紹
From mobile apps to microservices, from small startups to big enterprises, Gradle helps teams build, autom ate and deliver better software, faster.
可以看到Gradle不僅是手機(jī)應(yīng)用逗柴,還可以應(yīng)用于后臺(tái),Gradle到使命簡(jiǎn)單來說就是幫忙工程構(gòu)建顿肺,更快戏溺,更自動(dòng)化,更可控屠尊,更便捷旷祸。
回到Android側(cè),Gradle是目前Android主流的構(gòu)建工具知染,不管你是通過命令行還是通過AndroidStudio來build肋僧,最終都是通過Gradle來實(shí)現(xiàn)的。
說到打包控淡,我們來看下Java打包到三大山嫌吠。
Java生態(tài)體系中有三大構(gòu)建工具:Ant、Maven和Gradle掺炭。其中辫诅,Ant是由Apache軟件基金會(huì)維護(hù);Maven這個(gè)單詞來自于意第緒語(猶太語)涧狮,意為知識(shí)的積累炕矮,最初在Jakata Turbine項(xiàng)目中用來簡(jiǎn)化構(gòu)建過程;Gradle是一個(gè)基于Apache Ant和Apache Maven概念的項(xiàng)目自動(dòng)化構(gòu)建開源工具者冤,它使用一種基于Groovy的特定領(lǐng)域語言(DSL)來聲明項(xiàng)目設(shè)置肤视,拋棄了基于XML的各種繁瑣配置。
三涉枫、Gradle/Groovy/Java/JVM/Kotlin關(guān)系
最初看到Gradle的時(shí)候會(huì)發(fā)現(xiàn)他和Java的語法很像 邢滑,但又有區(qū)別,再到后面了解Groovy愿汰,學(xué)習(xí)Kotlin困后,他們之間的關(guān)系對(duì)于新學(xué)習(xí)Gradle系統(tǒng)的人來說會(huì)很懵乐纸。
如果來畫一個(gè)他們之間的關(guān)系,其實(shí)就比較清楚的體現(xiàn)了他們之間的關(guān)系摇予。
從上面我們會(huì)有一個(gè)比較直觀的理解汽绢,首先從上到下,Gradle不屬于Language層侧戴,就像上面描述的宁昭,Gradle是一個(gè)框架,是一個(gè)幫助我們工程編譯的框架救鲤。而往下的Language層久窟,就是我們的Java/Kotlin/Groovy秩冈,雖然三個(gè)都屬于Language層本缠,但是還是有一定的歸屬關(guān)系,Groovy和Kotlin是基于Java的DSL入问,所以Groovy和Kotlin是可以無縫調(diào)用Java的丹锹。
DSL:Domain Specific Language 的縮寫,中文的翻譯為領(lǐng)域特定語言(下簡(jiǎn)稱DSL);而與DSL相對(duì)的就是GPL芬失,這里的GPL并不是我們知道的開源許可證楣黍,而是General Purpose Language的簡(jiǎn)稱,即通用編程語言棱烂,也就是我們非常熟悉的Objective-C租漂、Java、Python颊糜、以及C語言等哩治。
DSL 通過在表達(dá)能力上做的妥協(xié)換取在某一領(lǐng)域內(nèi)的高效。它們的表達(dá)能力有限衬鱼,只是在特定領(lǐng)域解決特定任務(wù)的业筏。
我對(duì)DSL的理解是,DSL是依附于某一特殊場(chǎng)景鸟赫,或者專注于某一領(lǐng)域蒜胖,通過大量的語法糖,來便捷這一領(lǐng)域的開發(fā)抛蚤。有來這樣的理解台谢,我們來看下屬于DSL有哪些:SQL,CSS,HTML,Groovy,Kotlin。會(huì)發(fā)現(xiàn)特征就很明顯岁经。所以可以看到Groovy和Kotlin都是基于Java的DSL朋沮,所以再回頭往上看,Gradle可以用Kotlin/Java編寫嗎蒿偎?答案肯定是朽们,完全沒問題怀读,只是缺少來語法糖的支持,肯定寫起來會(huì)枯草很多骑脱。(當(dāng)然還是指的Java,Kotlin編寫Gradle腳本還是很爽的)再往下看菜枷,我們就到來真正運(yùn)行的地方,class文件叁丧,剛才說到的Groovy/Kotlin/Java啤誊,最終都會(huì)編譯成class文件,變成JVM能夠運(yùn)行的字節(jié)碼文件拥娄,最終運(yùn)行起來蚊锹。
四、Gradle版本號(hào)和Gradle Plugin版本號(hào)的關(guān)系
記得剛從Eclipse轉(zhuǎn)到Android Studio的時(shí)候稚瘾,特別痛苦牡昆,經(jīng)常各種莫名其妙的報(bào)錯(cuò),說什么版本對(duì)應(yīng)不上摊欠。
Project is using an old version of the Android Gradle plug-in. The minimum supported version is x.x.x Please update the version of the dependency 'com.android.tools.build:gradle'
這時(shí)候就會(huì)很懵丢烘,版本對(duì)應(yīng)不上,而且都是gradle些椒,怎么一個(gè)工程里面有兩個(gè)gradle版本播瞳,搜索項(xiàng)目會(huì)發(fā)現(xiàn)還真是有兩個(gè)定義gralde版本的地方。
//build.gradle
classpath 'com.android.tools.build:gradle:3.5.1'
//gradle-wrapper.properties
distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
所以這里剛一看到就會(huì)感到很奇怪免糕,這兩個(gè)Gradle到底哪個(gè)是真正的Gradle赢乓,各有什么作用呢?
所以這里就來介紹一下石窑,先說一下Gradle和Android Studio是完全兩個(gè)沒有關(guān)系的東西牌芋,Gradle有一套自己的環(huán)境,就像我們安裝Java一樣尼斧,需要配置環(huán)境變量等等姜贡,然后也可以通過命令行執(zhí)行操作,類似于javac,那么怎么能讓AS便捷的使用Gradle呢棺棵,所以Google就針對(duì)Gradle和AS的結(jié)合楼咳,編寫了一個(gè)Android Gradle Plugin,所以我們能在AS上使用Gradle完全是因?yàn)檫@個(gè)插件的原因烛恤。
它本質(zhì)就是一個(gè)AS插件母怜,它一邊調(diào)用Gradle本身的代碼和批處理工具來構(gòu)建項(xiàng)目,一邊調(diào)用Android SDK的編譯缚柏、打包功能苹熏,從而讓我們能夠順暢的在AS上進(jìn)行開發(fā)。
Gradle插件跟Android SDK Build Tool有關(guān)聯(lián),因?yàn)樗€承接著Android Studio里的編譯相關(guān)的功能轨域,這也是我們要在項(xiàng)目的local.properties文件里寫Android SDK路徑袱耽,在build.gradle里注明buildToolsVersion的原因。
所以現(xiàn)在我們?cè)賮砜瓷蟽蓚€(gè)定義的版本就會(huì)發(fā)現(xiàn)干发,classpath 'com.android.tools.build:gradle:3.0.0'
是用來定義Android Gradle Plugin的版本朱巨,對(duì)應(yīng)的distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
就是用來定義Gradle的版本的。
Gradle插件是獨(dú)立于AndroidStudio運(yùn)行的枉长,所以它的更新也是AndroidStudio分開的冀续。Gradle插件會(huì)有版本號(hào),每個(gè)版本號(hào)又對(duì)應(yīng)一個(gè)或者一些Gradle發(fā)行版本(一般是限定一個(gè)最低版本)
所以我們的插件的版本和Gradle的版本一定要對(duì)應(yīng)上必峰,具體的對(duì)應(yīng)關(guān)系官方地址
但這里其實(shí)我很想吐槽一下洪唐,既然是插件,對(duì)于Gradle的包裝吼蚁,為什么不直接內(nèi)部指定好Gradle的版本號(hào)凭需,還需要開發(fā)者自己手動(dòng)去對(duì)應(yīng)Gradle Plugin和Gradle的關(guān)系,從一個(gè)插件或者產(chǎn)品的角度來看桂敛,我感覺這樣的設(shè)計(jì)是有待優(yōu)化的功炮。
五溅潜、Gradle文件目錄結(jié)構(gòu)
接下來我們來看下和Gradle相關(guān)的目錄結(jié)構(gòu)术唬,通過對(duì)目錄結(jié)構(gòu)對(duì)了解,也有助于我們后面對(duì)于Gradle編譯原理對(duì)理解滚澜。
首先我們看到了上面的目錄結(jié)構(gòu)粗仓,這個(gè)是我們新建的一個(gè)工程的目錄結(jié)構(gòu)。
local.properties
sdk.dir=/xxxxx/xxxxxx/Library/Android/sdk
local.properties是構(gòu)建系統(tǒng)配置本地環(huán)境屬性设捐,其中包括:
- ndk.dir —— NDK路徑借浊。此屬性已被棄用,NDK的所有下載版本都安裝在Android SDK目錄下的NDK目錄中萝招。
- sdk.dir —— SDK的路徑蚂斤。
- cmake.dir —— CMake的路徑。
- ndk.symlinkdir —— 在Android Studio 3.5以及更高的版本中槐沼,創(chuàng)建指向NDK的符號(hào)鏈接曙蒸,該符號(hào)鏈接的路徑可比SDK安裝路徑短。
setting.gradle
setting.gradle文件位于項(xiàng)目的根目錄下岗钩,用于指示Gradle在構(gòu)建應(yīng)用時(shí)將哪些模塊包含在內(nèi)纽窟。對(duì)于單工程來說,這個(gè)文件的作用很小浓领,一般是這樣的陶因。
include ':app'
但是如果我們創(chuàng)建一個(gè)子Module椒涯,就會(huì)發(fā)現(xiàn)這個(gè)文件的內(nèi)容發(fā)生了改變径密。
include ':app'
include ':subModule'
所以這個(gè)文件就是當(dāng)我們工程進(jìn)行組件化和模塊化的很重要的文件审孽。
gradle.properties
用于配置項(xiàng)目全局Gradle設(shè)置县袱,如Gradle守護(hù)程序的最大堆大小,有時(shí)候我們?nèi)值囊恍┡渲糜恿Γ热缛肿兞肯匀部梢栽谶@個(gè)文件進(jìn)行配置,所有的Module都可以讀取到搓萧。
但這里要提一個(gè)問題:這個(gè)文件可以有多個(gè)嗎杂数?如果多個(gè)的話,會(huì)是怎樣的效果呢瘸洛、這里大家可以自己試下揍移,我這里就直接給結(jié)論了。
這個(gè)文件可以多個(gè)反肋,但是根目錄下的配置會(huì)全局生效那伐,也就是如果我們?cè)诟夸浥渲昧艘粋€(gè)變量COMMON__VERSION,所有的子Module都可以讀取到石蔗,如果我們?cè)谧禹?xiàng)目中也新建一個(gè)gradle.properties也配置了一個(gè)COMMON_VERSION變量罕邀,那么會(huì)覆蓋根目錄的版本。
gradle--wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-rc-1-all.zip
這個(gè)文件的從名字上來看养距,意思就很直觀诉探,就是包了一層Gradle,其實(shí)他的作用也是這樣的棍厌,經(jīng)常有這樣的場(chǎng)景肾胯,我們每個(gè)人本地的Gradle版本可能不一致,每個(gè)項(xiàng)目的Gradle版本也可能不一致耘纱,這樣就可能出現(xiàn)版本不一致而導(dǎo)致編譯不通過的問題敬肚,所以為了解決這個(gè)問題,Gradle官方出了gradle-wrapper的機(jī)制束析,表示該項(xiàng)目使用什么版本來進(jìn)行編譯艳馒,這樣假如我們本地是Gradle2.0,拉下來的gradle--wrapper的配置是gradle-4.1,這時(shí)候我們就會(huì)使用這個(gè)Gradle版本進(jìn)行編譯员寇。
build.gradle
這個(gè)就是重頭戲了弄慰,這就是我們用于打包編寫的Gradle腳本,里面可以看到我們寫的依賴關(guān)系丁恭,打包配置等等一系列配置和打包邏輯曹动,這個(gè)這里就不展開講了,后面會(huì)專門展開講解牲览,這里還是從文件結(jié)構(gòu)的角度來看下這個(gè)文件墓陈,這里有兩個(gè)build.gradle文件恶守,如果我們看下,同樣的兩個(gè)文件層級(jí)是不一樣的贡必。
在根目錄下的build.gradle常用于配置我們的全局屬性兔港,當(dāng)在這個(gè)文件配置后,我們所有的子項(xiàng)目都會(huì)生效仔拟、
在子項(xiàng)目目錄下的build.gradle,就是我們針對(duì)這個(gè)項(xiàng)目的單獨(dú)的配置衫樊。
六、總結(jié)
這篇博客從基礎(chǔ)上講解了我認(rèn)為在第一次接觸Gradle可能遇到的一些困惑點(diǎn)利花,算是對(duì)Gradle先有了一個(gè)大體上的了解科侈,接下來會(huì)繼續(xù)講解Gradle,第二篇博客可能對(duì)Gradle的配置進(jìn)行講解炒事。