Android Gradle為我們提供了大量的DSL,我們使用這些DSL定義配置我們的工程以滿足我們項目中不同的需求。這些DSL有很多,在上一章演示Android Gradle工程示例的時候,我們已經(jīng)大概介紹了compileSdkVersion、buildToolsVersion以及defaultConfig等,這一章我們再詳細(xì)介紹一些常用的DSL配置,這些配有有簽名信息、構(gòu)建類型、代碼混淆、zipAlign對齊壓縮等。
8.1 defaultConfig默認(rèn)配置
defaultConfig是android對象中的一個配置塊,負(fù)責(zé)定義所有的默認(rèn)配置,它是一個ProductFlavor,如果一個ProductFlavor沒有被特殊定義配置的話,默認(rèn)就會使用defaultConfig{}塊指定的配置,比如包名、版本號、版本名稱等。
一個基本上的defaultConfig配置如下:

以上示例配置了Android 開發(fā)的基本信息,可以滿足一個基本的Android App開發(fā),下面我們對它的一些配置進(jìn)行一個詳細(xì)的說明。
8.1.1 applicationId
applicationId是ProductFlavor的一個屬性,用于指定生成的App的包名,默認(rèn)情況下是null,這時候在構(gòu)建的時候,會從我們的AndroidManifest.xml文件中讀取,也就是我們在AndroidManifest.xml文件中配置的manifest標(biāo)簽的package屬性值。
8.1.2 minSdkVersion
minSdkVersion是ProductFlavor的一個方法,對應(yīng)的方法原型是
public void minSdkVersion(int minSdkVersion) {
this.setMinSdkVersion(minSdkVersion);
}
它可以指定我們的App最低支持的Android 操作系統(tǒng)版本,其對應(yīng)的值是Android SDK的API LEVEL,根據(jù)這里的方法原型,它接受的值是一個整數(shù),除此之外,它還有以下兩種方法原型定義:

根據(jù)我們前面講的Gradle知識,發(fā)現(xiàn)minSdkVersion也是一個屬性,它也可以接受一個字符串作為它的值,在這里明確一下,這個字符串不是我們SDK API LEVEL的字符串形式,而是Code Name,也就是我們的每個Android SDK或者說是Android OS的代號。就是我們新聞上經(jīng)常見到的什么‘冰激凌三明治’什么的。這里給出一個列表,讓大家一目了然。

8.1.3 targetSdkVersion
這個用于配置我們基于哪個Android SDK開發(fā),它的可選值和minSdkVersion一樣,沒有配置的時候也會從AndroidManifest.xml文件中讀取,參考minSdkVersion的介紹,這里就不多做介紹了。
8.1.4 versionCode
它也是ProductFlavor的一個屬性,用于配置Android App的內(nèi)部版本號,是一個整數(shù)值,通常用于版本的升級。沒有配置的時候從AndroidManifest.xml文件中讀取,建議配置。其方法原型是
public class DefaultProductFlavor extends BaseConfigImpl implements ProductFlavor {
...
public ProductFlavor setVersionCode(Integer versionCode) {
this.mVersionCode = versionCode;
return this;
}
public Integer getVersionCode() {
return this.mVersionCode;
}
...
}
8.1.5 versionName
versionName和versionCode類似,也是ProductFlavor一個屬性,用于配置Android App的版本名稱,比如V1.0.0等等,主要顯示用,讓用戶或者市場知道我們的Android App版本,它和versionCode一個是外部用,一個是內(nèi)部使用,一起配合完成Android App的版本控制,其方法原型是
public ProductFlavor setVersionName(String versionName) {
this.mVersionName = versionName;
return this;
}
public String getVersionName() {
return this.mVersionName;
}
8.1.6 testApplicationId
用于配置測試App的包名,默認(rèn)情況下是applicationId + “.test”,一般情況下默認(rèn)即可,它也是ProductFlavor的一個屬性,方法原型是
public ProductFlavor setTestApplicationId(String applicationId) {
this.mTestApplicationId = applicationId;
return this;
}
public String getTestApplicationId() {
return this.mTestApplicationId;
}
8.1.7 testInstrumentationRunner
用于配置單元測試時使用的Runner,默認(rèn)使用的是android.test.InstrumentationTestRunner,如果你想使用自己自定義的Runner,修改這個值即可,它也是一個屬性,其方法原型是
public ProductFlavor setTestInstrumentationRunner(String testInstrumentationRunner) {
this.mTestInstrumentationRunner = testInstrumentationRunner;
return this;
}
public String getTestInstrumentationRunner() {
return this.mTestInstrumentationRunner;
}
8.1.8 signingConfig
配置默認(rèn)的簽名信息,用對生成的App簽名,它是一個SigningConfig,也是ProductFlavor的一個屬性,可以直接對其進(jìn)行配置,其方法原型是
public SigningConfig getSigningConfig() {
return this.mSigningConfig;
}
public ProductFlavor setSigningConfig(SigningConfig signingConfig) {
this.mSigningConfig = signingConfig;
return this;
}
8.1.9 proguardFile
用于配置App ProGuard混淆所使用的ProGuard配置文件,它是ProductFlavor的一個方法,接受一個文件作為參數(shù)。其方法原型為
public void proguardFile(Object proguardFile) {
this.getProguardFiles().add(this.project.file(proguardFile));
}
可以看到它可以被調(diào)用多次,調(diào)用一次添加一個,其參數(shù)被project.file方法轉(zhuǎn)換為一個文件對象。其具體使用我們在稍后進(jìn)行介紹。
8.1.10 proguardFiles
這個也是配置ProGuard配置文件,只不過它可以同時接受多個配置文件,因為它的參數(shù)是一個可變類型的參數(shù)。
public void proguardFiles(Object... files) {
Object[] var2 = files;
int var3 = files.length;
for(int var4 = 0; var4 < var3; ++var4) {
Object file = var2[var4];
this.proguardFile(file);
}
}
從方法實現(xiàn)我們可以看到,同時可以添加多個ProGuard配置,在實際情況下中可以選擇不同的配置方式。
8.2 配置簽名信息
一個App只有被簽名之后才能被發(fā)布、安裝、使用,簽名是保護(hù)App的方式,標(biāo)記該App的唯一性,如果App被惡意篡改,簽名就不一樣了,就無法升級安裝,一定程度上也保護(hù)了我們的App。
要對App進(jìn)行簽名,你先得有一個簽名證書文件,這個文件被開發(fā)者持有,我們這里假設(shè)你已經(jīng)有生成的證書,不對證書的生成進(jìn)行介紹了。
一般我們的App有debug和release兩種模式(下面會將構(gòu)建類型),在我們開發(fā)調(diào)試的時候使用的是debug模式,發(fā)布的時候使用release模式;我們可以針對這兩種模式采用不同的簽名方式,一般debug模式的時候,Android SDK已經(jīng)為我們提供了一個默認(rèn)的debug簽名證書,我們可以直接使用,但是發(fā)布的時候,release模式構(gòu)建時,我們要配置使用自己生成的簽名證書。
對于簽名信息的配置,Android Gradle為我們提供了非常簡便的方式,讓我們可以非常容易的配置一個簽名信息以供調(diào)用。

Android Gradle為我們提供了signingConfigs{}配置塊便于我們生成多個簽名配置信息。signingConfigs是android的一個方法,它接受一個域?qū)ο笞鳛槠鋮?shù),前面我們講過的,其類型是NamedDomainObjectContainer<SigningConfig>,這樣我們在signingConfigs{}塊中定義的都是一個SigningConfig。一個SigningConfig就是一個簽名配置,其可配置的元素如下:
- storeFile 簽名證書文件
- storePassword 簽名證書文件的密碼
- storeType 簽名證書的類型
- keyAlias 簽名證書中密鑰別名
- keyPassword 簽名證書中該密鑰的密碼
例子中我們定義配置了一個名為release的簽名配置,除此之外,我們還可以配置多個不同的簽名前置,比如我們添加一個debug的配置。

默認(rèn)情況下,debug模式的簽名已經(jīng)被配置好了,使用的就是Android SDK自動生成的debug證書,它一般位于$HOME/.android/debug.keystore,其Key和密碼都是已知的,一般情況下我們不需要單獨配置debug模式的簽名信息。
現(xiàn)在我們配置好了兩個簽名信息,但是他們還沒有被使用,現(xiàn)在只是生成了兩個SigningConfig的實例,一個變量名為release,一個為debug,如果要使用他們我們只需引用他們即可,比如在8.1.8節(jié)中我們講配置默認(rèn)的簽名信息,現(xiàn)在我們就可以引用debug的配置信息使用。

可以看到我們在defaultConfig中對簽名配置的應(yīng)用這里的signingConfigs是android對象實例的一個屬性,對應(yīng)是getSigningConfigs(),debug就是我們上面創(chuàng)建的簽名配置名稱。
除了上面的默認(rèn)簽名配置之外,我們也可以對構(gòu)建的類型分別配置簽名信息,比如我上面說的debug模式配置debug的簽名信息,release默認(rèn)配置release的簽名信息。

如果你還有其他類型,想為其配置單獨的簽名,也可以這么做,比如付費版的VIP,單獨進(jìn)行簽名配置、特別的渠道包單獨配置等等。
8.3 構(gòu)建的應(yīng)用類型
關(guān)于構(gòu)建類型,前面的章節(jié)我們已經(jīng)用到了一些,在Android Gradle工程中,Android Gradle已經(jīng)幫我們內(nèi)置了debug和release兩個構(gòu)建類型,他們兩種模式的只要差別在于能否在設(shè)備上調(diào)試以及簽名不一樣,其他代碼和文件資源都是一樣的,一般情況下也夠用了。
如果想增加新的構(gòu)建類型,在buildTypes{}代碼塊中繼續(xù)添加元素就好了。buildTypes和signingConfigs一樣,也是android的一個方法,接受的參數(shù)也是一個域?qū)ο驨amedDomainObjectContainer<BuildType>,添加的每一個都是BuildType類型,所以你可以使用BuildType提供的方法和屬性對現(xiàn)有的BuildType配置,這里列舉一些常用的配置。
8.3.1 applicationIdSuffix
applicationIdSuffix是BuildType的一個屬性,用于配置基于默認(rèn)applicationId的后綴,比如默認(rèn)defaultConfig中配置的applicationId為org.flysnow.app.example82,我們在debug的BuildType中指定applicationIdSuffix為.debug,那么構(gòu)建生成的debug apk的包名就是org.flysnow.app.example82.debug。其方法原型為
public BaseConfigImpl setApplicationIdSuffix(String applicationIdSuffix) {
this.mApplicationIdSuffix = applicationIdSuffix;
return this;
}
8.3.2 debuggable
debuggable也是BuildType的一個屬性,用于配置是否生成一個可供調(diào)試的Apk。其值可以為true或者false。其方法原型為
public BuildType setDebuggable(boolean debuggable) {
this.mDebuggable = debuggable;
return this;
}
8.3.3 jniDebuggable
jniDebuggable和debuggable類似,也是BuildType的一個屬性,用于配置是否生成一個可供調(diào)試Jni(C/C++)代碼的Apk。接受boolean類型的值
8.3.4 minifyEnabled
也是BuildType的一個屬性,用于配置該BuildType是否啟用Proguard混淆,接受一個boolean類型的值
8.3.5 multiDexEnabled
也是BuildType的一個屬性,用于配置該BuildType是否啟用自動拆分多個Dex的功能,一般用于代碼太多,超過了65535個方法的時候,進(jìn)行的拆分為多個Dex的處理,后面會詳細(xì)講使用。接受一個boolean類型的值
8.3.6 proguardFile
是BuildType的一個方法,用于配置Proguard混淆使用的配置文件,和前面講的defaultConfig中的proguardFile一樣
8.3.7 proguardFiles
是BuildType的一個方法,用于配置Proguard混淆使用的配置文件,該方法可以同時配置多個Proguard配置文件
8.3.8 shrinkResources
是BuildType的一個屬性,用于配置是否自動清理未使用的資源,默認(rèn)為false.
這是一個非常有用的功能,我們在后面的章節(jié)會詳細(xì)介紹。
8.3.9 signingConfig
配置該BuildType使用的簽名配置,前面已經(jīng)講過,可以參考8.2章節(jié)溫習(xí)一遍。
每一個BuildType都會生成一個SourceSet,默認(rèn)位置為src/<buildtypename>/,根據(jù)我們以前講的知識,一個SourceSet包含源代碼、資源文件等信息,在Android中就包含了我們的java源代碼,res資源文件以及AndroidManiftest文件等,所以針對不同的BuildType,我們可以單獨的為其指定Java源代碼,res資源等,只要把他們放到src/<buildtypename>/下相應(yīng)的位置即可,在構(gòu)建的時候,Android Gradle會優(yōu)先使用他們代替我們main下的相關(guān)文件。
另外需要注意,因為我們的每個BuildType都會生成一個SourceSet,所以新增的BuildType名字一個要注意,不能是main和androidTest,因為他們兩個已經(jīng)被系統(tǒng)占用,同事每個BuildType之間名稱不能相同。
除了會生成對應(yīng)的SourceSet外,每一個BuildType還會生成相應(yīng)的assemble<BuildTypeName>任務(wù),比如我們常用的assembleRelease和assembleDebug就是Android Gradle自動生成的兩個Task任務(wù),他們是release和debug這兩個BuildType自動創(chuàng)建生成的。執(zhí)行相應(yīng)的assemble<BuildTypeName>任務(wù),就能生成對應(yīng)BuildType的所有Apk。
8.4 使用混淆
代碼混淆是一個非常有用的功能,它不僅可能優(yōu)化我們的代碼,讓我們的Apk包變得更小,還可以混淆我們原來的代碼,讓反編譯的人不容易看明白我們業(yè)務(wù)邏輯,很難分析。一般情況下我們發(fā)布到市場的版本一定是要混淆的,也就是我們的release模式編譯的版本,但是我們自己調(diào)試的版本不用混淆,因為混淆后就無法斷點跟蹤調(diào)試了,也就是我們的debug模式。
要啟用混淆,我們把BuildType的屬性minifyEnabled的值設(shè)置為true即可。
現(xiàn)在我們啟用了混淆,但是Android Gradle還不知道按何種規(guī)則進(jìn)行混淆,不知道要保留哪些類不混淆,要做到這些就需要我們的Proguard配置文件了,現(xiàn)在我們?yōu)槲覀兊幕煜付ㄅ渲梦募?/p>
根據(jù)我們8.3小結(jié)講的知識,指定Proguard配置文件我們可以使用proguardFile方法,也可以使用proguardFiles方法,這個根據(jù)情況而定,看你是想指定一個還是想同時指定多個。
這里我們注意到,使用了一個getDefaultProguardFile方法,該方法是android實例的一個方法,全限定寫法可以這樣android.getDefaultProguardFile,它的作用是獲取我們Android SDK安裝目錄中,Android為我們提供的默認(rèn)Proguard混淆配置文件,路徑是Android SDK安裝目錄下的tools/proguard文件夾中,我們看下該方法的原型

從實現(xiàn)中看,我們只需傳遞一個文件名給這個方法,他就會返回tools/proguard目錄下的該文件的絕對路徑。
Android SDK默認(rèn)為我們提供了兩個Proguard配置文件,他們分別是proguard-android.txt和proguard-android-optimize.txt,一個是沒有優(yōu)化的,一個是優(yōu)化的,你可以根據(jù)情況自己選擇,當(dāng)然你也可以都不用,全部自己定義,自己定義的時候可以參考Proguard官方網(wǎng)站文檔,查看相關(guān)配置說明,網(wǎng)址為 http://proguard.sourceforge.net/ 。
除了在BuildType中啟用混淆和配置混淆外,我們也可以在defaultConfig中啟用和配置,還記得我們前面在8.1章節(jié)講的吧,因為這個是默認(rèn)配置,一般用的比較少。
我們還可以針對個別渠道,啟用和配置Proguard混淆,多渠道包是通過productFlavors配置的,productFlavors是一個NamedDomainObjectContainer<ProductFlavor>域?qū)ο?,其配置的渠道本質(zhì)上就是一個ProductFlavor,和defaultConfig是一樣的,所以每個渠道也可以單獨的啟用和配置Proguard混淆。
8.5 啟用zipalign優(yōu)化
zipalign是Android為我們提供的一個整理優(yōu)化Apk文件的工具,它能提供系統(tǒng)和應(yīng)用的運(yùn)行效率,更快的讀寫Apk中的資源,降低內(nèi)存的使用,所以對于我們要發(fā)布的App,在發(fā)布之前一定要使用zipalign進(jìn)行優(yōu)化。
Android Gradle為我們提供了開啟zipalign優(yōu)化更簡便的方式,我們只需要配置開啟即可,剩下的操作,比如調(diào)用SDK目錄下的zipalign工具進(jìn)行處理等,Android Gradle會幫我們搞定。要為我們的release模式開啟zipalign優(yōu)化的話,只需進(jìn)行如下配置即可。
zipAlignEnabled是BuildType的一個屬性,接受一個boolean類型的值.
8.6 小結(jié)
這一章對我們Android Gradle常用的DSL做了詳細(xì)的講解說明,并且盡可能對常用的屬性方法配置也進(jìn)行了詳細(xì)的說明,同時配有每個屬性和方法的源代碼實現(xiàn),讓大家對這些配置有個更深的認(rèn)識。大家可以靈活的使用這些DSL對自己的項目進(jìn)行自定義構(gòu)建,以滿足自己的項目需求。
本文屬自學(xué)歷程, 僅供參考
詳情請支持原書 Android Gradle權(quán)威指南