Android中Gradle入門詳解

什么是gradle

Gradle 是新一代的自動(dòng)化構(gòu)建工具,它是一個(gè)獨(dú)立的項(xiàng)目,跟 AS、Android 無關(guān),官方網(wǎng)站:https://gradle.org/ , 類似 Ant、Maven這類構(gòu)建工具都是基于 xml 來進(jìn)行描述的,很臃腫,而 Gradle 采用的是一種叫做 Groovy 的語言,語法跟 Java 語法很像,但是是一種動(dòng)態(tài)語言,而且在 Java 基礎(chǔ)上做了不少改進(jìn),用起來更加簡潔、靈活,而且 Gradle 完全兼容 Maven、Ivy,這點(diǎn)基本上宣布了 Maven、Ivy 可以被拋棄了,Gradle 的推出主要以 Java 應(yīng)用為主,當(dāng)然目前還支持 Android、C、C++。

Gradle 與 Android Studio 的關(guān)系

上面也提到,Gradle 跟 Android Studio 其實(shí)沒有關(guān)系,但是 Gradle 官方還是很看重 Android 開發(fā)的,Google 在推出 AS 的時(shí)候選中了 Gradle 作為構(gòu)建工具,為了支持 Gradle 能在 AS 上使用,Google 做了個(gè) AS 的插件叫 Android Gradle Plugin ,所以我們能在 AS 上使用 Gradle 完全是因?yàn)檫@個(gè)插件的原因。在項(xiàng)目的根目錄有個(gè) build.gradle 文件,里面有這么一句代碼:

classpath 'com.android.tools.build:gradle:2.1.2'

這個(gè)就是依賴 gradle 插件的代碼,后面的版本號(hào)代表的是 android gradle plugin 的版本,而不是 Gradle 的版本,這個(gè)是 Google 定的,跟 Gradle 官方?jīng)]關(guān)系。

Gradle Wrapper

現(xiàn)在默認(rèn)新建一個(gè)項(xiàng)目,然后點(diǎn)擊 AS 上的運(yùn)行,默認(rèn)就會(huì)直接幫你安裝 Gradle ,我們不需要額外的安裝 Gradle 了,但是其實(shí)這個(gè) Gradle 不是真正的 Gradle ,他叫 Gradle Wrapper ,意為 Gradle 的包裝,什么意思呢?假設(shè)我們本地有多個(gè)項(xiàng)目,一個(gè)是比較老的項(xiàng)目,還用著 Gradle 1.0 的版本,一個(gè)是比較新的項(xiàng)目用了 Gradle 2.0 的版本,但是你兩個(gè)項(xiàng)目肯定都想要同時(shí)運(yùn)行的,如果你只裝了 Gradle 1.0 的話那肯定不行,所以為了解決這個(gè)問題,Google 推出了 Gradle Wrapper 的概念,就是他在你每個(gè)項(xiàng)目都配置了一個(gè)指定版本的 Gradle ,你可以理解為每個(gè) Android 項(xiàng)目本地都有一個(gè)小型的 Gradle ,通過這個(gè)每個(gè)項(xiàng)目你可以支持用不同的 Gradle 版本來構(gòu)建項(xiàng)目。

Gradle兩個(gè)基本概念:項(xiàng)目和任務(wù)

每個(gè) build.gradle 構(gòu)建腳本文件代表一個(gè)項(xiàng)目 project:



任務(wù) task 定義在構(gòu)建腳本里:


每次構(gòu)建至少包括一個(gè)項(xiàng)目,每個(gè)項(xiàng)目里又至少包括一個(gè)任務(wù)。

在編譯過程中, Gradle 會(huì)根據(jù) build 相關(guān)文件,聚合所有的project和task,執(zhí)行task 中的 action。因?yàn)?build.gradle文件中的task非常多,先執(zhí)行哪個(gè)后執(zhí)行那個(gè)需要一種邏輯來保證。這種邏輯就是依賴邏輯,幾乎所有的Task 都需要依賴其他 task 來執(zhí)行,沒有被依賴的task 會(huì)首先被執(zhí)行。所以到最后所有的 Task 會(huì)構(gòu)成一個(gè) 有向無環(huán)圖(DAG Directed Acyclic Graph)的數(shù)據(jù)結(jié)構(gòu)。

構(gòu)建生命周期

一個(gè) Gradle 構(gòu)建通常包括下面三個(gè)階段:

  1. 初始化
    項(xiàng)目實(shí)例會(huì)在這時(shí)被創(chuàng)建,如果這個(gè)項(xiàng)目里有多個(gè) module,或者依賴多個(gè) library,并且它們都有對(duì)應(yīng)的 build.gradle 文件,就會(huì)創(chuàng)建多個(gè)項(xiàng)目實(shí)例
  2. 配置
    在這個(gè)階段構(gòu)建腳本被執(zhí)行,并且為每個(gè)項(xiàng)目實(shí)例創(chuàng)建和配置任務(wù)
  3. 執(zhí)行
    在這個(gè)階段 Gradle 將根據(jù)構(gòu)建腳本的配置決定哪些任務(wù)會(huì)被執(zhí)行

初識(shí)Gradle文件

我們用 Android Studio 新創(chuàng)建一個(gè)項(xiàng)目時(shí),會(huì)自動(dòng)生成 3 個(gè) Gradle 文件:


setting.gradle

setting.gradle 文件在 初始化過程中被執(zhí)行,構(gòu)建器通過 setting.gradle 文件中的內(nèi)容了解哪些模塊將被 build,下面的內(nèi)容表明當(dāng)前項(xiàng)目中除了 app 模塊還有另外一個(gè)叫做 “shixinlibrary” 的依賴模塊:

include ‘:app’, ‘:shixinlibrary’

注意:單模塊項(xiàng)目不一定需要有 setting 文件,但一旦有多個(gè)模塊,必須要有 setting 文件,同時(shí)也要寫明所有要構(gòu)建的模塊,否則 gradle 不會(huì) build 不包括的模塊。

主目錄下的 build.gradle

看 gradle 文件中的注釋:

Top-level build file where you can configuration options common to all sub-projects/modules.

主目錄下的 build.gradle 文件是最頂層的構(gòu)建文件,這里配置所有模塊通用的配置信息。

默認(rèn)的頂層 build.gradle 文件中包括兩個(gè)代碼塊 (buildscript 和 allprojects):

buildscript

從名字就可以看出來,buildscript 是所有項(xiàng)目的構(gòu)建腳本配置,主要包括依賴的倉庫和依賴的 gradle 版本。

上圖中 repositories 代碼塊將 jcenter 配置為一個(gè)倉庫,JCenter 是一個(gè)很有名的 Maven 倉庫。確定了依賴的倉庫后,我們就可以在 dependencies 代碼塊中添加依賴的、在 jcenter 倉庫中的包了。

如果倉庫有密碼,也可以同時(shí)傳入用戶名和密碼

repositories {
        jcenter()
        mavenCentral()
        maven { 
            url "https://dl.bintray.com/thelasterstar/maven/"
            credentials {
                username 'user'
                password 'secretpassword'
            }
        }
    }

dependencies 代碼塊用于配置構(gòu)建過程中的依賴包,注意,這里是用于構(gòu)建過程,因此你不能將你的應(yīng)用模塊中需要依賴的庫添加到這里。

默認(rèn)情況下唯一被用于構(gòu)建過程中的依賴包是 Gradle for Android 的插件。我們還可以添加一些其他用于構(gòu)建的插件,比如 retrolambda, apt, freeline 等等。

allprojects

allprojects 代碼塊用來聲明將被用于所有模塊的屬性,注意是所有模塊。常見的就是配置倉庫地址(jcenter, 自定義 maven 倉庫等),你還可以在 allprojects 中創(chuàng)建 tasks,這些 tasks 最終會(huì)運(yùn)用到所有模塊中,

官方建議盡量少添加用于所有模塊的屬性,因?yàn)檫@意味著強(qiáng)耦合,一旦沒有構(gòu)建主項(xiàng)目,你的子模塊很有可能因?yàn)槿鄙偎心K的屬性導(dǎo)致構(gòu)建失敗。

模塊下的 build.gradle

模塊下的 build.gradle 文件只應(yīng)用于當(dāng)前模塊,你可以覆蓋主目錄下的 build.gradle 的內(nèi)容。


上圖中主要分三個(gè)模塊:apply plugin , android, dependencies。

apply plugin

apply plugin 聲明了接下來要用到哪些插件的內(nèi)容,上圖表明使用了 androd 插件,這里之所以能用 android 插件,是因?yàn)橹髂夸浿新暶髁?Gradle for Android 的依賴,這里才能使用。

因此當(dāng)我們需要使用其他插件,比如 retrolambda 時(shí),首先需要在主目錄 build.gradle 文件中添加依賴,然后在模塊 build.gradle 中聲明使用 retrolambda 插件。

備注:默認(rèn)的 android 插件是由 Google 官方維護(hù)的,為我們提供了構(gòu)建、測(cè)試、打包 Android 應(yīng)用的能力。除此之外我們還可以自定義插件。在逐漸加深對(duì) Gradle 的了解后,我們將嘗試自己寫個(gè) Gradle 插件。

android

在聲明了 android 插件后,我們就可以使用 android 插件提供的內(nèi)容進(jìn)行構(gòu)建配置。
android 構(gòu)建配置中必須要有的是兩個(gè)版本:

  • compileSdkVersion : 編譯應(yīng)用的 Android API 版本
  • buildToolsVersion : 構(gòu)建工具版本 (android studio3.0上已經(jīng)不需要了)

defaultConfig 代碼塊用于配置應(yīng)用的默認(rèn)屬性,可以覆蓋 AndroidManifest.xml 中的屬性,比如:

  • applicationId : 覆蓋了 AndroidManifest 中的 package name
  • minSdkVersion : 覆蓋了 AndroidManifest 中的屬性,配置運(yùn)行應(yīng)用的最小 API
  • targetSdkVersion : 一樣,用于通知系統(tǒng)當(dāng)前應(yīng)用已經(jīng)被這個(gè)版本測(cè)試過,和之前的 compileSdkVersion 沒有關(guān)系
  • versionCode : 一樣,應(yīng)用的版本號(hào)
  • versionName : 版本名稱

defaultConfig 還可以添加簽名,占位符等等,這里只列這些。
buildTypes 用來定義如何構(gòu)建和打包不同類型的應(yīng)用,常見的就是測(cè)試和生產(chǎn)。
android 中還可以配置其他信息,比如 簽名、渠道等,你可以在 Project Structure 面板中直觀的查看,添加,也可以使用代碼添加


dependencies

上圖中可以看到 依賴配置 在 android 代碼塊的外邊,事實(shí)上依賴配置是 Gradle 配置的基礎(chǔ)功能,也就是說除了 Android,其他類型的項(xiàng)目(比如 JavaEE )也可以這么用。

我們可以在依賴配置中,添加要使用的庫,當(dāng)然也可以添加本地的 jar 包。

Android項(xiàng)目中的Gradle實(shí)踐

版本的統(tǒng)一管理

當(dāng)我們的工程中有許多module的時(shí)候,分開管理編譯版本,minsdk將會(huì)是一件很麻煩的事,因?yàn)橐粋€(gè)library的改動(dòng),可能會(huì)影響到其他module。這時(shí)我們就需要對(duì)所有的版本進(jìn)行統(tǒng)一的管理:

我們可以把一些需要用的字段都放在project的build.gradle(注意是project的不是module的)中:

ext {   
 compileSdk = 21    
 minSdk = 11    
 targetSdk = 23    
 support = "23.1.1"   
 buildTools = "21.0.1"   
 buildstyle ="debug"
}

這樣,在module的build.gradle中可以進(jìn)行讀取:

defaultConfig {   
 applicationId "android.com.testgradle"    
 minSdkVersion rootProject.ext.minSdk    
 targetSdkVersion rootProject.ext.targetSdk    
 versionCode 1   
 versionName "1.0"
}

多版本打包( Build Variant)

BuildType

默認(rèn)情況下,Android plugin會(huì)自動(dòng)的構(gòu)建release和debug兩個(gè)版本

buildTypes {
    release {
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
    debug {
        minifyEnabled false
    }
}
// release版本中設(shè)置了開啟混淆,并且定義了混淆文件的位置

Android plugin允許自定義這兩個(gè)示例,并且可以創(chuàng)建其他的buildType,如下:

buildTypes {
    debug {
        minifyEnabled false
        applicationIdSuffix ".debug"
    }
    custom.initWith(buildTypes.debug)
    custom {
        applicationIdSuffix ".custom"
        versionNameSuffix "-customs"
    }
}

上述配置進(jìn)行了一下設(shè)置:

  • 對(duì)默認(rèn)的debug構(gòu)建類型進(jìn)行了修改,關(guān)閉了混淆配置,添加applicationId后綴
  • 以debug為基礎(chǔ)創(chuàng)建一個(gè)叫custom的構(gòu)建類型(相當(dāng)于繼承了debug版本),在custom的構(gòu)建類型中修改applicationId后綴,并添加了versionName的后綴。

Source sets

gradle通過一個(gè)叫SourceSets的概念來尋找和關(guān)聯(lián)要編譯的源碼文件,每當(dāng)創(chuàng)建一個(gè)新的build type 的時(shí)候,gradle 默認(rèn)都會(huì)創(chuàng)建一個(gè)新的source set。我們可以建立與main文件夾同級(jí)的文件夾,根據(jù)編譯類型的不同我們可以選擇對(duì)某些源碼和資源文件直接進(jìn)行替換。



對(duì)于每一個(gè)BuildType,Android plugin都會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的sourceSet,默認(rèn)位置為:src/BuildTypeName
所以新建BuildType的名字不能是main、androidTest和test這三個(gè)已經(jīng)被用的名字

BuildType的代碼/資源會(huì)以以下方式進(jìn)行合并

  • manifest會(huì)被合并到app的manifest文件中
  • res目錄下的資源文件會(huì)替換main里的資源文件
  • java目錄下的文件會(huì)被添加到main里的java目錄中,所以不能和main里的類重名(含包名)

除此之外,不同編譯類型的項(xiàng)目,我們的依賴都可以不同,比如,如果我需要在staging和debug兩個(gè)版本中使用不同的log框架,我們這樣配置:


Product flavors

Product flavors 默認(rèn)不引用,我們可以手動(dòng)添加,同Build type一樣,每一個(gè)Product flavors 版本也都有屬于自己的Source sets,也可以差異化設(shè)置構(gòu)建屬性。

當(dāng)同時(shí)設(shè)置了BuildType和Product flavors后,二者會(huì)組合構(gòu)建,最多可以生成m×n個(gè)版本的apk包。對(duì)于二者SourceSets,重復(fù)的res文件覆蓋原則buildType>Product flavors

在一些情況下,一個(gè)應(yīng)用可能需要基于多個(gè)標(biāo)準(zhǔn)來創(chuàng)建多個(gè)版本。
例如,有個(gè) app 需要一個(gè)免費(fèi)版本和一個(gè)付費(fèi)的版本,并且需要在不同的 app 發(fā)布平臺(tái)發(fā)布。這個(gè) app 需要 2 個(gè)付費(fèi)版和 2 個(gè)特定發(fā)布平臺(tái),因此就需要生成 4 個(gè)APK(不算 Build Types 生成的 Variant 版本)。

然而,這款 app 中,為 2 個(gè)發(fā)布平臺(tái)構(gòu)建的付費(fèi)版本源代碼都是相同,因此創(chuàng)建 4 個(gè) flavor 來實(shí)現(xiàn)不是一個(gè)好辦法。 如果使用兩個(gè) flavor 維度,兩兩組合,構(gòu)建所有可能的 Variant 組合才是最好的。

這個(gè)功能的實(shí)現(xiàn)就是使用 Flavor Dimensions 。每一個(gè) Dimensions 代表一個(gè)維度,并且 flavor 都被分配到一個(gè)指定的 Dimensions 中。

android {
...
flavorDimensions 'price', 'store'

productFlavors {
    google {
        dimension 'store'
    }

    amazon {
        dimension 'store'
    }

    free {
        dimension 'price'
    }

    paid {
        dimension 'price'
    }
}
}
/* 注:
dimension參數(shù)在gradle2.0之后替換掉了flavorDimension參數(shù),所以很多文章里依然使用的類似于如下寫法:
google {
        flavorDimension 'store'
    }
    
flavorDimension參數(shù)現(xiàn)已失效
*/

andorid.flavorDimensions 數(shù)組按照先后排序定義了可能使用的 Dimensions 。每一個(gè) Product Flavor 都被分配到一個(gè) Dimensions 中。

上面的例子中將 Product Flavor 分為兩組(即兩個(gè)維度),分別為 price 維度 [free, paid] 和 store 維度 [google, amazon] ,再加上默認(rèn)的 Build Type 有 [debug, release] ,這將會(huì)組合生成以下的 Build Variant:

  • free-google-debug
  • free-google-release
  • free-amazon-debug
  • free-amazon-release
  • paid-google-debug
  • paid-google-release
  • paid-amazon-debug
  • paid-amazon-release

每一個(gè) Variant 版本的配置由幾個(gè) Product Flavor 對(duì)象決定:

  • 一個(gè)來自 price 組中的對(duì)象
  • 一個(gè)來自 store 組中的對(duì)象

android.flavorDimensions 中定義的 Dimensions 排序非常重要(Variant 命名和優(yōu)先級(jí)等)。

flavorDimensions 中的排序決定了哪一個(gè) flavor 覆蓋哪一個(gè),這對(duì)于資源來說非常重要,因?yàn)橐粋€(gè) flavor 中的值會(huì)替換定義在低優(yōu)先級(jí)的 flavor 中的值。

flavorDimensions 使用最高的優(yōu)先級(jí)定義,因此在上面例子中的優(yōu)先級(jí)為:

price > store > defaultConfig

android studio 3.0的一些變化

不再需要指定則不需要再指定buildToolsVersion了,會(huì)根據(jù)compileSdkVersion自動(dòng)匹配合適的版本。

compile標(biāo)簽依然可用,但是已經(jīng)過時(shí),替代標(biāo)簽為api和implementation
api標(biāo)簽==compile


api對(duì)比implement

在java文件中,選中你要轉(zhuǎn)換的代碼,然后在頂部選擇Code——>Convert Java File to Kotlin File進(jìn)行轉(zhuǎn)換就好了,轉(zhuǎn)換之后,這就是一個(gè)Kotlin文件了。

Android Monitor分離為logcat和Android Profiler
支持java1.8,支持lamda表達(dá)式,并提示轉(zhuǎn)換
新的文件資源管理器

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 說明 本文主要介紹和Gradle關(guān)系密切、相對(duì)不容易理解的配置,偏重概念介紹。部分內(nèi)容是Android特有的(例如...
    jzj1993閱讀 15,712評(píng)論 1 62
  • 1.介紹 如果你正在查閱build.gradle文件的所有可選項(xiàng),請(qǐng)點(diǎn)擊這里進(jìn)行查閱:DSL參考 1.1新構(gòu)建系統(tǒng)...
    Chuckiefan閱讀 12,166評(píng)論 8 72
  • 在 Android Studio 構(gòu)建的項(xiàng)目中,基于 Gradle 進(jìn)行項(xiàng)目的構(gòu)建,同時(shí)使用 Android DS...
    Ant_way閱讀 7,413評(píng)論 0 16
  • 所有Android插件的基本擴(kuò)展。 你不需要直接使用這個(gè),你可以選擇下面幾個(gè)合適的直接使用 AppExtensio...
    我該忘了我自己w_u閱讀 3,420評(píng)論 0 5
  • 什么是gradle Gradle 是新一代的自動(dòng)化構(gòu)建工具,它是一個(gè)獨(dú)立的項(xiàng)目,跟 AS、Android 無關(guān),官...
    ZSGZ_AD閱讀 5,830評(píng)論 2 11