1、如何在app級(jí)別的gradle.build文件中增加自動(dòng)簽名
在android {}中增加以下配置
// 增加自動(dòng)簽名的內(nèi)容
signingConfigs {
config {
keyAlias KEY_ALIAS
keyPassword KEY_PASSWORD
storeFile file(STORE_FILE)
storePassword STORE_PASSWORD
}
}
buildTypes {
debug {
// 增加簽名設(shè)置
signingConfig signingConfigs.config
}
release {
// 增加簽名設(shè)置
signingConfig signingConfigs.config
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
我們預(yù)先在gradle.properties文件中藏好了簽名的信息:
KEY_ALIAS=test
KEY_PASSWORD=test
STORE_FILE=D\:\\Android\\sinatrue\\test_sign.jks
STORE_PASSWORD=test
然后在signingConfigs{} 中引用了gradle.properties中的簽名信息。
之后在buildTypes{} 中增加簽名設(shè)置。
這樣一來(lái),構(gòu)建出來(lái)的apk文件就自動(dòng)打上了簽名。
2、如何根據(jù)不同的ABI生成不同的apk
在gradle.build文件中的android {}中增加以下配置
splits {
// Configures multiple APKs based on ABI.
abi {
// Enables building multiple APKs per ABI.
enable true
// By default all ABIs are included, so use reset() and include to specify that we only
// want APKs for x86 and x86_64.
// Resets the list of ABIs that Gradle should create APKs for to none.
reset()
// Specifies a list of ABIs that Gradle should create APKs for.
include "x86", "x86_64", "arm64-v8a", "armeabi-v7a"
// Specifies that we do not want to also generate a universal APK that includes all ABIs.
universalApk false
}
}
- enable true 是否開(kāi)啟根據(jù)ABI生成多個(gè)apk;
- reset() 清空ABI列表;
- include 設(shè)置具體需要的ABI;
- universalApk false 是否生成一個(gè)包含所有ABI的apk文件。
設(shè)置好之后,雙擊擊構(gòu)建腳本,就可以生成不同ABI的apk文件。

3、如何修改構(gòu)建出的apk文件名
在app級(jí)別的gradle.build文件的android {}中添加下面代碼:
android.applicationVariants.all {
variant ->
variant.outputs.all { output ->
outputFileName = "xxx.apk"
}
}
"xxx"就是最終得到的文件名,文件格式是apk。
4、如何實(shí)現(xiàn)多渠道打包
假如現(xiàn)在我一套代碼需要打包成如圖所示的四個(gè)apk文件:

它們分別是應(yīng)用名“accountbook”、“notebook”和藍(lán)色啟動(dòng)圖標(biāo)、紅色啟動(dòng)圖標(biāo)的組合。
4.1、定義風(fēng)格維度
在app級(jí)別的gradle.build文件的android {}中定義風(fēng)格維度。有多少項(xiàng)就會(huì)有多少維度。下面定義了'appName', 'iconColor'兩個(gè)維度。
flavorDimensions 'appName', 'iconColor'
4.2、定義每個(gè)維度對(duì)應(yīng)有多少風(fēng)格
如本例中appName 有 accountbook 和 notebook 兩種風(fēng)格;iconColor 有 redIcon 和 blueIcon 兩種風(fēng)格。
最終編譯出來(lái)的產(chǎn)品,就是兩個(gè)維度風(fēng)格的組合。
如本例中共有accountbookredIcon、accountbookblueIcon、notebookredIcon、notebookblueIcon四種產(chǎn)品。
productFlavors {
accountbook {
dimension 'appName'
applicationId 'com.stranger.accountbook'
applicationIdSuffix '.endaccountbook'
versionCode 66
versionName 'a1'
versionNameSuffix 'a2'
}
notebook {
dimension 'appName'
applicationId 'com.stranger.notebook'
applicationIdSuffix '.endnotebook'
versionCode 77
versionName 'n1'
versionNameSuffix 'n2'
}
redIcon {
dimension 'iconColor'
applicationId 'com.stranger.redIcon'
applicationIdSuffix '.endredIcon'
versionCode 88
versionName 'r1'
versionNameSuffix 'r2'
}
blueIcon {
dimension 'iconColor'
applicationId 'com.stranger.blueIcon'
applicationIdSuffix '.endblueIcon'
versionCode 99
versionName 'b1'
versionNameSuffix 'b2'
}
}
4.3、得到每個(gè)產(chǎn)品的構(gòu)建腳本
點(diǎn)擊sync之后,就可以在androidstudio的右邊腳本欄的build中看到每一個(gè)產(chǎn)品對(duì)應(yīng)的構(gòu)建腳本。

4.4、如何將具體的某一個(gè)apk安裝到手機(jī)、模擬器
此時(shí)點(diǎn)擊Androidstudio的工具欄的綠色三角,安裝的是上面組合中的第一個(gè)組合的apk。

想要安裝具體某一個(gè)的apk,可以在右邊腳本欄的install腳本中找到具體腳本。點(diǎn)擊想安裝的即可安裝到手機(jī)、模擬器。

4.5、怎么做到將差異資源分別打包到各個(gè)產(chǎn)品apk
上面的步驟,雖然已經(jīng)可以打包得到四個(gè)apk文件,但是它們的名稱(chēng)和啟動(dòng)圖標(biāo)都是一樣的。如何做到將差異資源打包到四個(gè)apk中呢?
記得我們做多語(yǔ)言適配、橫豎屏布局文件的做法吧?這里是類(lèi)似的。
-
4.5.1、我們首先在app目錄下創(chuàng)建與main文件夾同級(jí)的文件夾,名稱(chēng)分別是我們?cè)賞roductFlavors{}中定義的四種productFlavor。
image.png -
4.5.2、appName維度我們需要不同的應(yīng)用名稱(chēng),所以我們?cè)赼ccountbook和notebook中創(chuàng)建和main同路徑同文件名的strings.xml
image.png
然后分別在它們中定義app_name。注意name和main中的保持一致,都是“app_name”。
image.png
image.png
通過(guò)上面的步驟,我們就可以打包出不同應(yīng)用名的apk了。
- 4.5.3 在redicon和blueicon中創(chuàng)建啟動(dòng)圖標(biāo)。
image.png
不要看到上面這么多mipmap的目錄就覺(jué)得很復(fù)雜,其實(shí)就是在redIcon中創(chuàng)建了紅色啟動(dòng)圖標(biāo)、在blueIcon中創(chuàng)建了藍(lán)色啟動(dòng)圖標(biāo)而已。(復(fù)習(xí)一下啟動(dòng)圖標(biāo)相關(guān)知識(shí)?)
創(chuàng)建好的圖標(biāo)名稱(chēng)依然叫ic_launcher,和main中保持一致。
經(jīng)過(guò)上面的工作,我們現(xiàn)在就可以構(gòu)建出不同應(yīng)用名不同啟動(dòng)圖標(biāo)的apk了。

安裝到手機(jī)上,就是下面的樣子:

4.6、差異代碼怎么辦
上面的做法只是實(shí)現(xiàn)了差異資源的打包。那如果我每個(gè)產(chǎn)品還有差異代碼呢,這時(shí)候該怎么辦?
其實(shí),編譯生成的BuildConfig類(lèi)就包含了我們的productFlavors的信息。我們可以在代碼中判斷當(dāng)前屬于哪一個(gè)productFlavor,從而做出差異化處理。
if (BuildConfig.FLAVOR_appName == "accountbook" && BuildConfig.FLAVOR_iconColor == "redIcon") {
//do something different.
}
if (BuildConfig.FLAVOR_appName == "accountbook" && BuildConfig.FLAVOR_iconColor == "blueIcon") {
//do something different.
}
if (BuildConfig.FLAVOR_appName == "notebook" && BuildConfig.FLAVOR_iconColor == "redIcon") {
//do something different.
}
if (BuildConfig.FLAVOR_appName == "notebook" && BuildConfig.FLAVOR_iconColor == "blueIcon") {
//do something different.
}
4.7、applicationId和versionName的拼接問(wèn)題
再來(lái)看一下,我們的productFlavors是這樣定義的:
productFlavors {
accountbook {
dimension 'appName'
applicationId 'com.stranger.accountbook'
applicationIdSuffix '.endaccountbook'
versionCode 66
versionName 'a1'
versionNameSuffix 'a2'
}
notebook {
dimension 'appName'
applicationId 'com.stranger.notebook'
applicationIdSuffix '.endnotebook'
versionCode 77
versionName 'n1'
versionNameSuffix 'n2'
}
redIcon {
dimension 'iconColor'
applicationId 'com.stranger.redIcon'
applicationIdSuffix '.endredIcon'
versionCode 88
versionName 'r1'
versionNameSuffix 'r2'
}
blueIcon {
dimension 'iconColor'
applicationId 'com.stranger.blueIcon'
applicationIdSuffix '.endblueIcon'
versionCode 99
versionName 'b1'
versionNameSuffix 'b2'
}
}
我們?yōu)槊恳粋€(gè)productFlavor都定義了applicationId、versionCode、applicationIdSuffix 、versionName 、versionNameSuffix 。
最后會(huì)拼接處什么樣的applicationId和versionName 呢?
在A(yíng)ndroidstudio中雙擊其中一個(gè)apk文件,自動(dòng)打開(kāi)apk分析器,點(diǎn)擊里面的AndroidManifest.xml,可以看到拼接結(jié)果。

這個(gè)package應(yīng)該就是拼接后的applicationId吧。不信的話(huà)我們?cè)俅蜷_(kāi)output-metadata.json文件。

從結(jié)果可以看出,
- 只有第一個(gè)維度的applicationId、versionCode、versionName會(huì)完整拼接,后面維度的都被忽略了。
- 所有維度applicationIdSuffix 、versionNameSuffix ,都會(huì)被拼接。
所以,我們保留第一維度的applicationId、versionCode、versionName,其它維度的applicationId、versionCode、versionName刪除;
而第一維度的各種后綴似乎并不需要,所以將它們刪除。
總的來(lái)說(shuō)就是第一維度定義前綴,后面維度定義后綴。
假如我們修改成下面的樣子:
productFlavors {
accountbook {
dimension 'appName'
applicationId 'com.stranger.accountbook'
versionCode 66
versionName 'a1'
}
notebook {
dimension 'appName'
applicationId 'com.stranger.notebook'
versionCode 77
versionName 'n1'
}
redIcon {
dimension 'iconColor'
applicationIdSuffix '.endredIcon'
versionNameSuffix 'r2'
}
blueIcon {
dimension 'iconColor'
applicationIdSuffix '.endblueIcon'
versionNameSuffix 'b2'
}
}
我們生成的apk文件名也修改一下:
android.applicationVariants.all {
variant ->
variant.outputs.all { output ->
def abiName = output.getFilter(com.android.build.OutputFile.ABI)
outputFileName = "${productFlavors[0].name}-${productFlavors[1].name}-$buildType.name-${abiName}-${productFlavors[0].versionName}-${productFlavors[1].versionNameSuffix}.apk"
}
}
{productFlavors[0].name}第一個(gè)風(fēng)格維度包含的名稱(chēng),在這里值是accountbook或notebook;
{productFlavors[1].name}第二個(gè)風(fēng)格維度包含的名稱(chēng),在這里值是redIcon或blueIcon;
{buildType.name}是構(gòu)建類(lèi)型,即debug或release;
{abiName}就是我們定義的不同ABI的名稱(chēng);
{productFlavors[0].versionName}第一個(gè)風(fēng)格維度的versionName,即accountbook或notebook的versionName;
{productFlavors[1].versionNameSuffix}第二個(gè)風(fēng)格維度的versionNameSuffix,即redIcon或blueIcon的versionNameSuffix 。
如此一來(lái),我們就可以構(gòu)建出不同應(yīng)用名、不同啟動(dòng)圖標(biāo)所對(duì)應(yīng)不同ABI的apk文件,而且apk文件的名稱(chēng)分別對(duì)應(yīng)的信息所拼成。

5、最后
最后貼上以上設(shè)置的所有內(nèi)容:
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.2"
defaultConfig {
applicationId "com.stranger.testflavor"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
// 增加自動(dòng)簽名的內(nèi)容
signingConfigs {
config {
keyAlias KEY_ALIAS
keyPassword KEY_PASSWORD
storeFile file(STORE_FILE)
storePassword STORE_PASSWORD
}
}
buildTypes {
debug {
// 增加簽名設(shè)置
signingConfig signingConfigs.config
}
release {
// 增加簽名設(shè)置
signingConfig signingConfigs.config
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
splits {
// Configures multiple APKs based on ABI.
abi {
// Enables building multiple APKs per ABI.
enable true
// By default all ABIs are included, so use reset() and include to specify that we only
// want APKs for x86 and x86_64.
// Resets the list of ABIs that Gradle should create APKs for to none.
reset()
// Specifies a list of ABIs that Gradle should create APKs for.
include "x86", "x86_64", "arm64-v8a", "armeabi-v7a"
// Specifies that we do not want to also generate a universal APK that includes all ABIs.
universalApk false
}
}
android.applicationVariants.all {
variant ->
variant.outputs.all { output ->
def abiName = output.getFilter(com.android.build.OutputFile.ABI)
outputFileName = "${productFlavors[0].name}-${productFlavors[1].name}-$buildType.name-${abiName}-${productFlavors[0].versionName}-${productFlavors[1].versionNameSuffix}.apk"
}
}
flavorDimensions 'appName', 'iconColor'
productFlavors {
accountbook {
dimension 'appName'
applicationId 'com.stranger.accountbook'
versionCode 66
versionName 'a1'
}
notebook {
dimension 'appName'
applicationId 'com.stranger.notebook'
versionCode 77
versionName 'n1'
}
redIcon {
dimension 'iconColor'
applicationIdSuffix '.endredIcon'
versionNameSuffix 'r2'
}
blueIcon {
dimension 'iconColor'
applicationIdSuffix '.endblueIcon'
versionNameSuffix 'b2'
}
}
}




