1、如何在app级别的gradle.build文件中增加自动签名
在android {}中增加以下配置
// 增加自动签名的内容
signingConfigs {
config {
keyAlias KEY_ALIAS
keyPassword KEY_PASSWORD
storeFile file(STORE_FILE)
storePassword STORE_PASSWORD
}
}
buildTypes {
debug {
// 增加签名设置
signingConfig signingConfigs.config
}
release {
// 增加签名设置
signingConfig signingConfigs.config
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
我们预先在gradle.properties文件中藏好了签名的信息:
KEY_ALIAS=test
KEY_PASSWORD=test
STORE_FILE=D\:\\Android\\sinatrue\\test_sign.jks
STORE_PASSWORD=test
然后在signingConfigs{} 中引用了gradle.properties中的签名信息。
之后在buildTypes{} 中增加签名设置。
这样一来,构建出来的apk文件就自动打上了签名。
2、如何根据不同的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 是否开启根据ABI生成多个apk;
- reset() 清空ABI列表;
- include 设置具体需要的ABI;
- universalApk false 是否生成一个包含所有ABI的apk文件。
设置好之后,双击击构建脚本,就可以生成不同ABI的apk文件。
3、如何修改构建出的apk文件名
在app级别的gradle.build文件的android {}中添加下面代码:
android.applicationVariants.all {
variant ->
variant.outputs.all { output ->
outputFileName = "xxx.apk"
}
}
"xxx"就是最终得到的文件名,文件格式是apk。
4、如何实现多渠道打包
假如现在我一套代码需要打包成如图所示的四个apk文件:
它们分别是应用名“accountbook”、“notebook”和蓝色启动图标、红色启动图标的组合。
4.1、定义风格维度
在app级别的gradle.build文件的android {}中定义风格维度。有多少项就会有多少维度。下面定义了'appName', 'iconColor'两个维度。
flavorDimensions 'appName', 'iconColor'
4.2、定义每个维度对应有多少风格
如本例中appName 有 accountbook 和 notebook 两种风格;iconColor 有 redIcon 和 blueIcon 两种风格。
最终编译出来的产品,就是两个维度风格的组合。
如本例中共有accountbookredIcon、accountbookblueIcon、notebookredIcon、notebookblueIcon四种产品。
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、得到每个产品的构建脚本
点击sync之后,就可以在androidstudio的右边脚本栏的build中看到每一个产品对应的构建脚本。
4.4、如何将具体的某一个apk安装到手机、模拟器
此时点击Androidstudio的工具栏的绿色三角,安装的是上面组合中的第一个组合的apk。
想要安装具体某一个的apk,可以在右边脚本栏的install脚本中找到具体脚本。点击想安装的即可安装到手机、模拟器。
4.5、怎么做到将差异资源分别打包到各个产品apk
上面的步骤,虽然已经可以打包得到四个apk文件,但是它们的名称和启动图标都是一样的。如何做到将差异资源打包到四个apk中呢?
记得我们做多语言适配、横竖屏布局文件的做法吧?这里是类似的。
-
4.5.1、我们首先在app目录下创建与main文件夹同级的文件夹,名称分别是我们再productFlavors{}中定义的四种productFlavor。
-
4.5.2、appName维度我们需要不同的应用名称,所以我们在accountbook和notebook中创建和main同路径同文件名的strings.xml
然后分别在它们中定义app_name。注意name和main中的保持一致,都是“app_name”。
通过上面的步骤,我们就可以打包出不同应用名的apk了。
- 4.5.3 在redicon和blueicon中创建启动图标。
不要看到上面这么多mipmap的目录就觉得很复杂,其实就是在redIcon中创建了红色启动图标、在blueIcon中创建了蓝色启动图标而已。(复习一下启动图标相关知识?)
创建好的图标名称依然叫ic_launcher,和main中保持一致。
经过上面的工作,我们现在就可以构建出不同应用名不同启动图标的apk了。
安装到手机上,就是下面的样子:
4.6、差异代码怎么办
上面的做法只是实现了差异资源的打包。那如果我每个产品还有差异代码呢,这时候该怎么办?
其实,编译生成的BuildConfig类就包含了我们的productFlavors的信息。我们可以在代码中判断当前属于哪一个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的拼接问题
再来看一下,我们的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'
}
}
我们为每一个productFlavor都定义了applicationId、versionCode、applicationIdSuffix 、versionName 、versionNameSuffix 。
最后会拼接处什么样的applicationId和versionName 呢?
在Androidstudio中双击其中一个apk文件,自动打开apk分析器,点击里面的AndroidManifest.xml,可以看到拼接结果。
这个package应该就是拼接后的applicationId吧。不信的话我们再打开output-metadata.json文件。
从结果可以看出,
- 只有第一个维度的applicationId、versionCode、versionName会完整拼接,后面维度的都被忽略了。
- 所有维度applicationIdSuffix 、versionNameSuffix ,都会被拼接。
所以,我们保留第一维度的applicationId、versionCode、versionName,其它维度的applicationId、versionCode、versionName删除;
而第一维度的各种后缀似乎并不需要,所以将它们删除。
总的来说就是第一维度定义前缀,后面维度定义后缀。
假如我们修改成下面的样子:
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}第一个风格维度包含的名称,在这里值是accountbook或notebook;
{productFlavors[1].name}第二个风格维度包含的名称,在这里值是redIcon或blueIcon;
{buildType.name}是构建类型,即debug或release;
{abiName}就是我们定义的不同ABI的名称;
{productFlavors[0].versionName}第一个风格维度的versionName,即accountbook或notebook的versionName;
{productFlavors[1].versionNameSuffix}第二个风格维度的versionNameSuffix,即redIcon或blueIcon的versionNameSuffix 。
如此一来,我们就可以构建出不同应用名、不同启动图标所对应不同ABI的apk文件,而且apk文件的名称分别对应的信息所拼成。
5、最后
最后贴上以上设置的所有内容:
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"
}
// 增加自动签名的内容
signingConfigs {
config {
keyAlias KEY_ALIAS
keyPassword KEY_PASSWORD
storeFile file(STORE_FILE)
storePassword STORE_PASSWORD
}
}
buildTypes {
debug {
// 增加签名设置
signingConfig signingConfigs.config
}
release {
// 增加签名设置
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'
}
}
}