使用場(chǎng)景:
1.應(yīng)用擁有付費(fèi)版和免費(fèi)版。2.應(yīng)用需要為各個(gè)平臺(tái)打包。3.其他需要產(chǎn)生不同版本的情況。
在AS中Gradle為我們默認(rèn)創(chuàng)建了兩個(gè)構(gòu)建類型(build types),還有另外一個(gè)概念 product flavor,它能讓我們更好的管理APP或library的各種版本。 Build types 和 product flavors 通常結(jié)合使用,他們統(tǒng)稱build variant。
構(gòu)建類型+定制產(chǎn)品=構(gòu)建變種版本,BuildType + ProductFlavor 任何一種組合都會(huì)是一個(gè)版本。
章節(jié)主題:
- Build types
- Product flavors
- Build variants
- Signing configurations
一,Build types
在Gradle 的Android plugin中,一個(gè)build type用來定義APP或library如何構(gòu)建。每個(gè)build type都能指定一些debug符號(hào)表,比如application ID,是否應(yīng)該混淆,無用資源是否應(yīng)該被刪除等等。這些參數(shù)在可以在 buildTypes block中定義,在AS中一個(gè)標(biāo)準(zhǔn)的buildTypes block如下:
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
buildTypes block默認(rèn)為我們生成了一個(gè)release版,minifyEnabled為true代表開啟混淆,shrinkResources為true代表刪除無用資源,proguardFiles 代表混淆規(guī)則文件名稱,第一個(gè)是Android自帶通用混淆規(guī)則,第二個(gè)是項(xiàng)目自定義混淆規(guī)則?;煜?guī)則編寫可以參考郭神的Android安全攻防戰(zhàn),反編譯與混淆技術(shù)完全解析(下)
1.創(chuàng)建build types
當(dāng)默認(rèn)的配置不能滿足需求時(shí),我們也能很簡(jiǎn)單的在buildTypes block里面配置相應(yīng)參數(shù)。如下一個(gè)創(chuàng)建staging的build type:
android {
buildTypes {
staging {
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
buildConfigField "String", "API_URL", "\"http://staging.example.com/api\""
}
}
}
staging為 application ID添加了后綴,使staging的application ID和 debug,release版本不同。比如:
Debug: com.package
Release: com.package
Staging: com.package.staging
這樣可以使你能在同一個(gè)設(shè)備上安裝Staging和release版,staging版本也有version名后綴。buildConfigField 在第二章介紹過。
在定義一個(gè)新的build type時(shí),也不需要從頭定義,可以摘抄一些其他build type的屬性, initWith()方法摘抄了debug type的屬性,當(dāng)定義了相同屬性會(huì)覆蓋。
android {
buildTypes {
staging.initWith(buildTypes.debug)
staging {
applicationIdSuffix ".staging"
versionNameSuffix "-staging"
debuggable = false
}
}
}
2.Source sets
當(dāng)創(chuàng)建一個(gè)新的 build type時(shí),Gradle也會(huì)創(chuàng)建一個(gè)新的source set,默認(rèn)source set和build type名稱相同,但是這個(gè)目錄不會(huì)默認(rèn)創(chuàng)建,需要自己去為build type創(chuàng)建source set目錄。你可以通過source set 為特定版本添加自定義代碼。
Resources在source set處理上有些特別,相同名稱的Drawables 和layout files將覆蓋main source set,但是
values 文件不會(huì),Gradle將合并不同的地方。
main source set的 strings.xml文件
<resources>
<string name="app_name">TypesAndFlavors</string>
<string name="hello_world">Hello world!</string>
</resources>
staging build type source set的 strings.xml文件
<resources>
<string name="app_name">TypesAndFlavors STAGING</string>
</resources>
merged strings.xml file
<resources>
<string name="app_name">TypesAndFlavors STAGING</string>
<string name="hello_world">Hello world!</string>
</resources>
3.Dependencies
每個(gè)build type都可以有它們自己的dependencies.例如在debug包里添加logging
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.2.0'
debugCompile 'de.mindpipe.android:android-logging-log4j:1.0.3'
}
二,Product flavors
與build type相比,Product flavors適用于為同一APP創(chuàng)建不同版本,典型的就是付費(fèi)和免費(fèi)版。為不同平臺(tái)生產(chǎn)不同版本。build type主要用于內(nèi)部使用,如果是發(fā)布到平臺(tái)上,而且想和已發(fā)布的版本區(qū)分開,就應(yīng)該使用 product flavors 。
1.創(chuàng)建product flavors
方法和build types類似,productFlavor block。
android {
productFlavors {
red {
applicationId 'com.gradleforandroid.red'
versionCode 3
}
blue {
applicationId 'com.gradleforandroid.blue'
minSdkVersion 14
versionCode 4
}
}
}
Product flavors和 build types擁有不同屬性,因?yàn)閜roduct flavors是ProductFlavor class 的對(duì)象。defaultConfig 對(duì)象在build scripts中,product flavors會(huì)共享 defaultConfig的屬性,所以可以在defaultConfig里配置product flavors的共同屬性。每個(gè)flavor也會(huì)覆蓋相同屬性。
2.多flavor variants
android {
flavorDimensions "color","price"
productFlavors{
red{
flavorDimension "color"
}
blue{
flavorDimension "color"
}
free{
flavorDimension "price"
}
paid{
flavorDimension "price"
}
}
}
例如上面,有付費(fèi)版和免費(fèi)版,顏色上面還有要求。要結(jié)合幾種情況,首先指定flavorDimensions屬性(在Android block中定義),然后分別在productFlavors block中指定版本,然后會(huì)產(chǎn)生以下幾種版本(結(jié)合build types)。
- blueFreeDebug and blueFreeRelease
- bluePaidDebug and bluePaidRelease
- redFreeDebug and redFreeRelease
- redPaidDebug and redPaidRelease
每個(gè)flavor都必須指定一個(gè)flavorDimension屬性, flavorDimensions 定義的屬性必須使用,順序也很重要,當(dāng)兩個(gè)類型結(jié)合時(shí),相同屬性會(huì)被前面的覆蓋,例如color覆蓋price的屬性。產(chǎn)生版本個(gè)數(shù)為:
總數(shù)=color屬性個(gè)數(shù) * price熟悉個(gè)數(shù) * build type個(gè)數(shù)(debug+release)
三,Build variants
Build variants是build types和product flavors結(jié)合的產(chǎn)物,在AS左側(cè)有Build Variants窗口可以查看各個(gè)版本,單擊即可構(gòu)建該版本。如果沒有指定 product flavors,Gradle的Android插件會(huì)默認(rèn)生成debug和release build type。

1.Tasks
Android plugin for Gradle會(huì)為每個(gè)build variant創(chuàng)建task。例如assembleDebug會(huì)構(gòu)建所有debug版本,assembleBlue會(huì)構(gòu)建所有blue版本。

2.Source sets
和 build type一樣,Build variants也擁有自己的source set,例如blue flavor 和free flavor的目錄,src/blueFreeDebug/java/,也可以使用sourceSets block指定目錄路徑。
3.Resource and manifest合并
在打包前Gradle會(huì)合并 main source set 和 build type source sets資源,library的資源也會(huì)被合并。當(dāng)在debug版本時(shí)想保存log文件,需要一些文件讀寫權(quán)限,但在正式版時(shí)不需要此權(quán)限,可以在debug 的source set里面申請(qǐng)額外的權(quán)限。
resources and manifests的優(yōu)先級(jí)順序:

在main source set和一個(gè)flavor中存在一個(gè)相同的resource時(shí),打包flavor時(shí)會(huì)使用flavor resource,而不是main source set。library的resource優(yōu)先級(jí)最低。
4.Creating build variants
android {
buildTypes {
debug {
buildConfigField "String", "API_URL",
"\"http://test.example.com/api\""
}
staging.initWith(android.buildTypes.debug)
staging {
buildConfigField "String", "API_URL",
"\"http://staging.example.com/api\""
applicationIdSuffix ".staging"
}
}
productFlavors {
red {
applicationId "com.gradleforandroid.red"
resValue "color", "flavor_color", "#ff0000"
}
blue {
applicationId "com.gradleforandroid.blue"
resValue "color", "flavor_color", "#0000ff"
}
}
}
如上定義,會(huì)產(chǎn)生build variants: blueDebug, blueStaging, redDebug, 和redStaging

staging build type 的 source set的drawable目錄下app icon和debug不同

5.Variant filters
有時(shí)需要過濾掉一些Variant 來加快assemble 命令。(assemble 構(gòu)建所有Variant )
//過濾掉release下的blue版本,這個(gè)task也被取消了??吹枚残?,反正我也寫不來(? ˙o˙)?
android.variantFilter { variant ->
if(variant.buildType.name.equals('release')) {
variant.getFlavors().each() { flavor ->
if (flavor.name.equals('blue')) {
variant.setIgnore(true);
}
}
}
}
四,Signing configurations
發(fā)布APK時(shí)需要簽名
android {
signingConfigs {
release {
//簽名文件路徑
storeFile file("release.keystore")
//簽名文件的密碼
storePassword "secretpassword"
//指定簽名文件的別名
keyAlias "gradleforandroid"
//指定簽名文件的別名配對(duì)密碼
keyPassword "secretpassword"
}
}
buildTypes {
release {
//指點(diǎn)簽名配置
signingConfig signingConfigs.release
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}