寄Android開發Gradle你需要知道的知識

19snow93發表於2018-05-07

當畢業不夠兩年,身邊的朋友慢慢得有車有房有女朋友週末有自己的節目,而我覺得很多美好的事情我都遙不可及,找不到可以讓自己開心的事情做,心情很不好。但是同時我覺得沉澱需要時間、努力、耐心和自律,所以我總相信艱難的時候是總會過去,迎接自己的美好生活總到來的,給自己喊一句:“加油!”。

好了,牢騷發完了,最近我看了《Android Gradle權威指南》這本書,雖然書上寫的內容可能比較簡單,但是對於Android開發人員來說應該還是比較夠用的了。所以,今天我打算結合書上的知識和自己開發專案作為例子來總結一篇關於Gradle的知識基礎要點。

初識Gradle

Gradle是一個基於Apache Ant和Apache Maven概念的專案自動化建構工具。它使用一種基於Groovy的特定領域語言來宣告專案設定,而不是傳統的XML。當前其支援的語言限於Java、Groovy和Scala,計劃未來將支援更多的語言。

怎麼看上面都是一段很官方的解釋,對於入門的人來說簡直是一個噩夢般的解釋(包括以前的我)。那下面我就用通俗一點語言說說我的理解。

Gradle就是工程的管理,幫我們做了依賴,打包,部署,釋出,各種渠道的差異管理等工作。舉個例子形容,如果我是一個做大事的少爺平時管不了這麼多小事情,那Gradle就是一個貼心的祕書或者管家,把一些雜七雜八的小事情都幫我們做好了,讓我們可以安心的打程式碼,其他事情可以交給管家管。

那有人會問,既然工作都可以交給他做,為什麼還要我們去了解。我想我們要管家做事,也要下達我們的命令,我們必須知道這些命令和管家的喜好才能跟他相處和諧,不然你不知道它的脾性下錯命令,那後果可是很嚴重的。

在以前實習的時候,我還用eclipse,那是匯入一個網上的下載的module還需要一步步的import。但自從用了Android Studio後,Gradle很貼心的幫我完成了這個繁雜的工作,而且往往只需要新增一句話,這太神奇了,當時我是這樣想的,下面我們也會說到這個。

分析

下面我就用自己專案中用到的Gradle慢慢分析:

寄Android開發Gradle你需要知道的知識

我們看到,每個Module都會對應有一個Gradle檔案,另外還有一個主Project的Gradle檔案管理全域性。下面我們先看看那個叫gradle-wrapper.properties的檔案:

gradle-wrapper

Wrapper是對Gradle的一層包裝,便於在團隊開發過程中統一Gradle構建的版本號,這樣大家都可以使用統一的Gradle版本進行構建。

寄Android開發Gradle你需要知道的知識
上面我們看到的圖就是Gradle提供內建的Wrapper task幫助我們自動生成Wrapper所需的目錄檔案。再看看我們Android專案裡面自動生成的檔案

寄Android開發Gradle你需要知道的知識
寄Android開發Gradle你需要知道的知識
終於,我們知道這幾個自動生成的檔案原來是Gradle Wrapper建立出來的。

那下面我們看看gradle-wrapper.properties這個檔案的作用

寄Android開發Gradle你需要知道的知識
看到專案裡面的各個屬性,下面再看看每個屬性的作用
寄Android開發Gradle你需要知道的知識
我們其實最關心的應該是distributionUrl這個屬性,他是下載Gradle的路徑,它下載的東西會出現在以下的資料夾中
寄Android開發Gradle你需要知道的知識
看到了吧,這個資料夾包含了各個版本你下載的Gradle。

當我是初學者的時候老是會遇到一個問題,那就是下圖:

寄Android開發Gradle你需要知道的知識
匯入專案的時候一直會停留在這個介面,這是為什麼?其實原因很簡單,就是你常用專案的Gradle版本跟你新匯入專案的Gradle版本不一致造成的,那怎麼解決?我本人自己是這麼做的:

  1. 網速好或者科學上網的時候,由它自己去下載,不過下載時間有長有短,不能保證。
  2. 當你在公司被限網速的時候,當然也是我最常用的,就是把你最近常用專案的gradle-wrapper.properties檔案替換掉你要匯入專案的該檔案,基本上我是這樣解決的,當然有時候也會遇到替換掉報錯的情況,不過比較少。

settings.gradle

下面我們講講settings.gradle檔案,它其實是用於初始化以及工程樹的配置的,放在根工程目錄下。

設定檔案大多數的作用都是為了配置自工程。在Gradle眾多工程是通過工程樹表示的,相當於我們在Android Studio看到的Project和Module概念一樣。根工程相當於Android Studio的Project,一個根工程可以有很多自工程,也就是很多Module,這樣就和Android Studio定義的Module概念對應上了。

寄Android開發Gradle你需要知道的知識
我們可以看到這個專案我們新增了7個module,一一對應,如果你的專案新增了專案依賴,那就會出現在這個檔案當中。

好了,我們說完settings.gradle檔案之後就慢慢進入其他檔案了,但是首先我們要解釋一下什麼是Groovy:

Groovy

Groovy是基於JVM虛擬機器的一種動態語言,它的語法和Java非常相似,由Java入門學習Groovy基本沒有障礙。Groovy完全相容Java,又在此基礎上增加了很多動態型別和靈活的特性,比如支援密保,支援DSL,可以說它就是一門非常靈活的動態指令碼語言。

一開始我總把Gradle和Groovy搞混了,現在我總把他們的關係弄清楚了。Gradle像是一個軟體,而Groovy就是寫這個軟體的語言,這就很簡單明瞭吧。那下面我們說到的內容都是用Groovy語法寫的,但是這個知識點我就暫時不科普了,有興趣的小夥伴可以去了解一下更深入的Groovy語法。

build.gradle(Project)

下面我們就來講講主的build.gradle檔案:

寄Android開發Gradle你需要知道的知識
我們這裡,分為四個標籤來講:

1.buildscript

buildscript中的宣告是gradle指令碼自身需要使用的資源。可以宣告的資源包括依賴項、第三方外掛、maven倉庫地址等

2.ext

ext是自定義屬性,現在很多人都喜歡把所有關於版本的資訊都利用ext放在另一個自己新建的gradle檔案中集中管理,下面我介紹一下ext是怎麼用的:

寄Android開發Gradle你需要知道的知識

  1. 首先我們新建兩個檔案,分別叫build.gradle和version.gradle

寄Android開發Gradle你需要知道的知識
寄Android開發Gradle你需要知道的知識

  1. 然後分別在兩個檔案中打上相應的程式碼

寄Android開發Gradle你需要知道的知識

  1. 最後在Android Studio的Terminal移動到相應的資料夾中執行task。

我們可以很神奇的發現,當我們在build.gradle檔案中輸入了apply from:'version.gradle'這句話,我們就可以讀取到該檔案下ext的資訊。

現在在專案中我也是這種方法統一管理所有第三方外掛的版本號的,有興趣的朋友也可以試試。

3.repositories

顧名思義就是倉庫的意思啦,而jcenter()、maven()和google()就是託管第三方外掛的平臺

4.dependencies

當然配置了倉庫還不夠,我們還需要在dependencies{}裡面的配置裡,把需要配置的依賴用classpath配置上,因為這個dependencies在buildscript{}裡面,所以代表的是Gradle需要的外掛。

下面我們再看看build.gradle(Project)的另一部分程式碼

寄Android開發Gradle你需要知道的知識

allprojects

allprojects塊的repositories用於多專案構建,為所有專案提供共同所需依賴包。而子專案可以配置自己的repositories以獲取自己獨需的依賴包。

奇怪,有人會問,為什麼同一個build.gradle(Project)檔案中buildscript和allprojects裡面的內容基本上是一樣的呢,他們的區別在哪?

buildscript和allprojects的作用和區別

buildscript中的宣告是gradle指令碼自身需要使用的資源,就是說他是管家自己需要的資源,跟你這個大少爺其實並沒有什麼關係。而allprojects宣告的卻是你所有module所需要使用的資源,就是說如果大少爺你的每個module都需要用同一個第三庫的時候,你可以在 allprojects裡面宣告。這下解釋應該可以明白了吧。

好了,下面該說說build.gradle(Project)檔案的最後一個一段程式碼了

寄Android開發Gradle你需要知道的知識

執行gradle clean時,執行此處定義的task。該任務繼承自Delete,刪除根目錄中的build目錄。相當於執行Delete.delete(rootProject.buildDir)。其實這個任務的執行就是可以刪除生成的Build檔案的,跟Android Studio的clean是一個道理。

build.gradle(Module)

講完Project的build檔案,就來講講最後也是內容最多的檔案了。

apply plugin

寄Android開發Gradle你需要知道的知識

首先要說下apply plugin:'×××'

這種叫做引入Gradle外掛,而Gradle外掛大致分為分為兩種:

  1. apply plugin:'×××':叫做二進位制外掛,二進位制外掛一般都是被打包在一個jar裡獨立釋出的,比如我們自定義的外掛,再發布的時候我們也可以為其指定plugin id,這個plugin id最好是一個全限定名稱,就像你的包名一樣;
  2. apply from:'×××':叫做應用指令碼外掛,其實這不能算一個外掛,它只是一個指令碼。應用指令碼外掛,其實就是把這個指令碼載入進來,和二進位制外掛不同的是它使用的是from關鍵字.後面緊跟的坫一個指令碼檔案,可以是本地的,也可以是網路存在的,如果是網路上的話要使用HTTP URL. 雖然它不是一個真正的外掛,但是不能忽視它的作用.它是指令碼檔案模組化的基礎,我們 可以把龐大的指令碼檔案.進行分塊、分段整理.拆分成一個個共用、職責分明的檔案,然後使 用apply from來引用它們,比如我們可以把常用的函式放在一個Utils.gradle指令碼里,供其他指令碼檔案引用。示例中我們把 App的版本名稱和版本號單獨放在一個指令碼檔案裡,清晰、簡單、方便、快捷.我們也可以使用自動化對該檔案自動處理,生成版本。

說說Gradle外掛的作用

把外掛應用到你的專案中,外掛會擴充套件專案的功能,幫助你在專案的構建過程中做很多事情。1.可以新增任務到你的專案中,幫你完成一些亊情,比如測試、編譯、打包。2.可以新增依賴配置到你的專案中,我們可以通過它們配置我們專案在構建過程中需要的依賴.比 如我們編譯的時候依賴的第三方庫等。3.可以向專案中現有的物件型別新增新的擴充套件屬性、 方法等,讓你可以使用它們幫助我們配置、優化構建,比如android{}這個配置塊就是Android Gradle外掛為Project物件新增的一個擴充套件。4. 可以對專案進行一些約定,比如應用Java插 件之後,約定src/main/java目錄下是我們的原始碼存放位置,在編譯的時候也是編譯這個目錄下的Java原始碼檔案。

然後我們說說'com.android.application'

Android Gradle外掛的分類其實是根據Android工程的屬性分類的。在Andriod中有3類工程,一類是App應用工程,它可以生成一個可執行的apk應用:一類是Library庫工程,它可以生成AAR包給其他的App工程公用,就和我們的Jar一樣,但是它包含了Android的資源等資訊,是一個特殊的Jar包;最後一類是Test測試工程,用於對App工程或者Library庫工程進行單元測試。

  1. App外掛id:com.android.application.
  2. Library外掛id:com.android.library.
  3. Test外掛id:com.android.test.

一般一個專案只會設定一個App外掛,而module一般是會設定為Library外掛。

寄Android開發Gradle你需要知道的知識

android{}

是Android外掛提供的一個擴充套件型別,可以讓我們自定義Android Gradle工程,是Android Gradle工程配置的唯一入口。

compileSdkVersion

是編譯所依賴的Android SDK的版本,這裡是API Level。

buildToolsVersion

是構建該Android工程所用構建工具的版本。

defaultConfig{}

defaultConfig是預設的配置,它是一個ProductFlavor。ProductFlavor允許我們根據不同的情況同時生成多個不同的apk包。

applicationId

配置我們的包名,包名是app的唯一標識,其實他跟AndroidManifest裡面的package是可以不同的,他們之間並沒有直接的關係。

package指的是程式碼目錄下路徑;applicationId指的是app對外發布的唯一標識,會在簽名、申請第三方庫、釋出時候用到。

minSdkVersion

是支援的Android系統的api level,這裡是15,也就是說低於Android 15版本的機型不能使用這個app。

targetSdkVersion

表明我們是基於哪個Android版本開發的,這裡是22。

versionCode

表明我們的app應用內部版本號,一般用於控制app升級,當然我在使用的bugly自動升級能不能接受到升級推送就是基於這個。

versionName

表明我們的app應用的版本名稱,一般是釋出的時候寫在app上告訴使用者的,這樣當你修復了一個bug並更新了版本,別人卻發現說怎麼你這個bug還在,你這時候就可以自信的告訴他自己看下app的版本號。(親身經歷在撕逼的時候可以從容的應對)

multiDexEnabled

用於配置該BuildType是否啟用自動拆分多個Dex的功能。一般用程式中程式碼太多,超過了65535個方法的時候。

ndk{}

多平臺編譯,生成有so包的時候使用,包括四個平臺'armeabi', 'x86', 'armeabi-v7a', 'mips'。一般使用第三方提供的SDK的時候,可能會附帶so庫。

sourceSets

原始碼集合,是Java外掛用來描述和管理原始碼及資源的一個抽象概念,是一個Java原始碼檔案和資原始檔的集合,我們可以通過sourceSets更改源集的Java目錄或者資源目錄等。

譬如像上圖,我通過sourceSets告訴了Gradle我的關於jni so包的存放路徑就在app/libs上了,叫他編譯的時候自己去找。

寄Android開發Gradle你需要知道的知識

name:build type的名字

applicationIdSuffix:應用id字尾

versionNameSuffix:版本名稱字尾

debuggable:是否生成一個debug的apk

minifyEnabled:是否混淆

proguardFiles:混淆檔案

signingConfig:簽名配置

manifestPlaceholders:清單佔位符

shrinkResources:是否去除未利用的資源,預設false,表示不去除。

zipAlignEnable:是否使用zipalign工具壓縮。

multiDexEnabled:是否拆成多個Dex

multiDexKeepFile:指定文字檔案編譯進主Dex檔案中

multiDexKeepProguard:指定混淆檔案編譯進主Dex檔案中
複製程式碼

buildType

構建型別,在Android Gradle工程中,它已經幫我們內建了debug和release兩個構建型別,兩種模式主要車別在於,能否在裝置上除錯以及簽名不一樣,其他程式碼和檔案資源都是一樣的。一般用在程式碼混淆,而指定的混淆檔案在下圖的目錄上,minifyEnabled=true就會開啟混淆:

寄Android開發Gradle你需要知道的知識

寄Android開發Gradle你需要知道的知識

signingConfigs

簽名配置,一個app只有在簽名之後才能被髮布、安裝、使用,簽名是保護app的方式,標記該app的唯一性。如果app被惡意刪改,簽名就不一樣了,無法升級安裝,一定程度保護了我們的app。而signingConfigs就很方便為我們提供這個簽名的配置。storeFile簽名檔案,storePassword簽名證照檔案的密碼,storeType簽名證照型別,keyAlias簽名證照中祕鑰別名,keyPassword簽名證照中改金鑰的密碼。

預設情況下,debug模式的簽名已經被配置好了,使用的就是Android SDK自動生成的debug證照,它一般位於$HOME/.android/debug.keystore,其key和密碼是已經知道的,一般情況下我們不需要單獨配置debug模式的簽名資訊。

寄Android開發Gradle你需要知道的知識

productFlavors

在我看來他就是Gradle的多渠道打包,你可以在不同的包定義不同的變數,實現自己的定製化版本的需求。

manifestPlaceholders

佔位符,我們可以通過它動態配置AndroidManifest檔案一些內容,譬如app的名字:

寄Android開發Gradle你需要知道的知識
看看上圖,我們就能發現我們在productFlavors中定義manifestPlaceholders = [APP_NAME: "(測試)"]之後,在AndroidManifest的label加上"${APP_NAME}",我們就能控制每個包打出來的名字是我們想要不同的名字,譬如測試伺服器和生產伺服器的包應該名字不一樣。

buildConfigField

他是BuildConfig檔案的一個函式,而BuildConfig這個類是Android Gradle構建指令碼在編譯後生成的。而buildConfigField就是其中的自定義函式變數,看下圖我們分別定義了三個常量:

寄Android開發Gradle你需要知道的知識
我們可以在BuildConfig檔案中看到我們宣告的三個變數

寄Android開發Gradle你需要知道的知識
然後我們就可以在程式碼中用這些變數控制不同版本的程式碼:
寄Android開發Gradle你需要知道的知識
我們這樣加個if,就可以輕輕鬆鬆的控制測試和生產版本付費的問題了,再也不用手動的改來改去了,那問題來了,我怎麼去選擇不同的版本呢,看下圖:

寄Android開發Gradle你需要知道的知識
如果你是Android Studio,找到Build Variants就可以選擇你當前要編譯的版本啦。

flavorDimensions

顧名思義就是維度,Gradle3.0以後要用flavorDimensions的變數必須在defaultConfig{}中定義才能使用,不然會報錯:

Error:All flavors must now belong to a named flavor dimension.
The flavor 'flavor_name' is not assigned to a flavor dimension.
複製程式碼

寄Android開發Gradle你需要知道的知識
這樣我們就可以在不同的包中形成不同的applicationId和versionName了。

寄Android開發Gradle你需要知道的知識

dexOptions{}

我們知道,Android中的Java原始碼被編譯成class位元組碼後,在打包成apk的時候 被dx命令優化成Android虛擬機器可執行的DEX檔案。DEX檔案比較緊湊,Android費盡心思 做了這個DEX格式,就是為了能使我們的程式在Android中平臺上執行快一些。對於這些生成 DEX檔案的過程和處理,Android Gradle外掛都幫我們處理好了,Android Gradle外掛會呼叫 SDK中的dx命令進行處理。但是有的時候可能會遇到提示記憶體不足的錯誤,大致提示異常是 java,lang.OutOfMemoryError: GC overhead limit exceeded,為什麼會提示記憶體不足呢? 其實這個 dx命令只是一個指令碼,它呼叫的還是Java編寫的dx.jar庫,是Java程式處理的,所以當記憶體 不足的時候,我們會看到這個Java異常資訊.預設情況下給dx分配的記憶體是一個G8,也就 是 1024MB。

所以我們只需要把記憶體設定大一點,就可以解決這個問題,上圖我的專案就把記憶體設定為4g。

寄Android開發Gradle你需要知道的知識

dependencies{}

我們平時用的最多的大概就這個了,

  1. 首先第一句compile fileTree(include: ['*.jar'], dir: 'libs'),這樣配置之後本地libs資料夾下的副檔名為jar的都會被依賴,非常方便。
  2. 如果你要引入某個本地module的話,那麼需要用compile project('×××')
  3. 如果要引入網上倉庫裡面的依賴,我們需要這樣寫compile group:'com.squareup.okhttp3',name:'okhttp',version:'3.0.1',當然這樣是最完整的版本,縮寫就把group、name、version去掉,然後以":"分割即可。 compile 'com.squareup.okhttp3:okhttp:3.0.1'
    寄Android開發Gradle你需要知道的知識
    但是到了gradle3.0以後build.gradle中的依賴預設為implementation,而不是 之前的compile。另外,還有依賴指令api。 那麼下面我們就來說說:

gradle 3.0中依賴implementation、api的區別:

其實api跟以前的compile沒什麼區別,將compile全部改成api是不會錯的; 而implementation指令依賴是不會傳遞的,也就是說當前引用的第三方庫僅限於本module內使用,其他module需要重新新增依賴才能用,下面用兩個圖說明:

寄Android開發Gradle你需要知道的知識

寄Android開發Gradle你需要知道的知識

相信看過圖的人都會一目明瞭。 好了,這期內容寫得差不多了,如果上面內容有什麼錯漏的話歡迎大家給我提出。雖然才講了gradle幾個檔案,但是感覺有些小眾內容還沒寫出來,如果後面有需要,我會補上的。今天就講這麼多了,下期再見!

我的簡書

相關文章