开发某个应用,基本功能是一样的,在打包的时候,区分渠道、配置不同的包名、签名。
1.新建一个工程
很简单,新建一个默认的 Hello World 工程就可以了。
2.新建对应渠道的文件夹
在 src 目录新建一个文件夹 qudao1 ,然后照着 main 文件的样子生成一样的目录,只需要目录,各目录下的文件先不要。
(要也不影响,本篇主要讲配置,不改代码)
在 src 目录新建一个文件夹 qudao2 ,操作同新建 qudao1 。
为了区分,我们简单修改下 string.xml ,
main 下的,
<resources>
<string name="app_name">OneAppMutilBale</string>
</resources>
qudao1 的,
<resources>
<string name="app_name">OneAppMutilBaleQudao1</string>
</resources>
qudao2 的,
<resources>
<string name="app_name">OneAppMutilBaleQudao2</string>
</resources>
3.配置渠道
修改 app 的 build.gradle ,
添加 sourceSets { }
,指明各个模块用的文件夹 。添加这个需要配置 flavorDimensions "app"
,要不然报错,app 可以替换成其他名称。
添加 productFlavors { }
,指明渠道,按渠道配置包名、版本号等。
applicationId
是最终生成的 apk 的包名。
其中的 base 、qudao1、qudao2 自己取名就行。
dimension 对应 flavorDimensions 。
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.cosmos.oneappmutilbale"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
flavorDimensions "app"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
base {
java.srcDir('src/main/java')
res.srcDir('src/main/res')
// assets.srcDir('src/main/assets')
// manifest.srcFile('src/main/AndroidManifest.xml')
}
qudao1 {
java.srcDir('src/qudao1/java')
res.srcDir('src/qudao1/res')
// assets.srcDir('src/qudao1/assets')
// manifest.srcFile('src/qudao1/AndroidManifest.xml')
}
}
}
productFlavors {
base {
applicationId "com.cosmos.oneappmutilbale"
dimension "app"
versionCode 1
versionName "1.0"
}
qudao1 {
applicationId "com.cosmos.oneappmutilbale.q1"
dimension "app"
versionCode 1
versionName "1.1"
}
}
applicationVariants.all {
variant ->
variant.outputs.all {
outputFileName = "OneAppMutilBale_${variant.productFlavors[0].name}_v${variant.productFlavors[0].versionName}.apk"
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
applicationVariants.all { }
部分是指定生成的 apk 的名字。
同步一下,如果在 Build Variants
栏出现多选,说明成功了。
4.配置不同的渠道签名
通过 AS 生成多个 jks 签名。(具体过程省略)
我新建了一个 jks 目录(路径 src/jks)用来存放 jks 签名文件。
修改 app 的 build.gradle ,
添加 signingConfigs { }
,指明 jks 路径和密码。其中的 signbase 、signqudao1 、signqudao2 自己取名就行。
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 30
defaultConfig {
applicationId "com.cosmos.oneappmutilbale"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
flavorDimensions "app"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
base {
java.srcDir('src/main/java')
res.srcDir('src/main/res')
// assets.srcDir('src/main/assets')
// manifest.srcFile('src/main/AndroidManifest.xml')
}
qudao1 {
java.srcDir('src/qudao1/java')
res.srcDir('src/qudao1/res')
// assets.srcDir('src/qudao1/assets')
// manifest.srcFile('src/qudao1/AndroidManifest.xml')
}
qudao2 {
java.srcDir('src/qudao2/java')
res.srcDir('src/qudao2/res')
// assets.srcDir('src/qudao2/assets')
// manifest.srcFile('src/qudao2/AndroidManifest.xml')
}
}
signingConfigs {
signbase {
storeFile file("src/jks/main.jks")
storePassword "123456"
keyAlias "keymain"
keyPassword "123456"
// 开启 V2 签名
v2SigningEnabled true
}
signqudao1 {
storeFile file("src/jks/qudao1.jks")
storePassword "789456"
keyAlias "keyqudao1"
keyPassword "789456"
v2SigningEnabled true
}
signqudao2 {
storeFile file("src/jks/qudao2.jks")
storePassword "456123"
keyAlias "keyqudao2"
keyPassword "456123"
v2SigningEnabled true
}
}
productFlavors {
base {
applicationId "com.cosmos.oneappmutilbale"
dimension "app"
versionCode 1
versionName "1.0"
signingConfig signingConfigs.signbase
}
qudao1 {
applicationId "com.cosmos.oneappmutilbale.q1"
dimension "app"
versionCode 1
versionName "1.1"
signingConfig signingConfigs.signqudao1
}
qudao2 {
applicationId "com.cosmos.oneappmutilbale.q2"
dimension "app"
versionCode 2
versionName "2.0"
signingConfig signingConfigs.signqudao2
}
}
applicationVariants.all {
variant ->
variant.outputs.all {
outputFileName = "OneAppMutilBale_${variant.productFlavors[0].name}_v${variant.productFlavors[0].versionName}.apk"
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
为了密码的安全的,可以把实际的信息写到 gradle.properties 文件中, build.gradle 引用即可。
gradle.properties 添加如下,
JKSFILE=/src/jks/main.jks
JKSPASSWORD=123456
KEYALIAS=keymain
KEYPASSWORD=123456
build.gradle 引用,
signingConfigs {
signbase {
storeFile file(JKSFILE)
storePassword JKSPASSWORD
keyAlias KEYALIAS
keyPassword KEYPASSWORD
// 开启 V2 签名
v2SigningEnabled true
}
// ...
}
5.修改图标
新建的工程,图标不是直接用的 drawable 下的图片,是这样用的,
android:roundIcon="@mipmap/ic_launcher_round"
ic_launcher_round.xml 内容如下,
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
</adaptive-icon>
ic_launcher_background.xml 内容如下,
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path
android:fillColor="#4DDC84"
android:pathData="M0,0h108v108h-108z" />
// ...
>
为了改出差异,将 main 目录下的 ic_launcher_background.xml 文件 拷贝到 qudao1 、qudao2 目录下,并放在对应的目录下(目录要一致,这很重要),
然后修改 android:fillColor 属性,换成不同的颜色就可以了。
引申,要用不同的资源文件,需要在对应渠道的对应目录下放入main文件夹下的同名文件,保证目录结构一样,然后修改渠道下的文件就可以了。
icon 、lable 、roundIcon 属性都是这样改。
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
有个点 mark 一样。Build Variants 切到 qudao1 时,修改 qudao1 下的 xml 才会有代码提示、并且不爆红。
so ,需要修改哪个渠道的东西,还是要先切到该渠道。
6.代码中判断渠道
在代码中如果需要判断渠道,用 BuildConfig
,它是编译生成的。和 productFlavors { }
里的信息一一对应 。
我的 demo 生成的,示例,
package com.cosmos.oneappmutilbale;
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String APPLICATION_ID = "com.cosmos.oneappmutilbale.q2";
public static final String BUILD_TYPE = "release";
public static final String FLAVOR = "qudao2";
public static final int VERSION_CODE = 2;
public static final String VERSION_NAME = "2.0";
}
7.安装验证
切换到需要的渠道,然后 build apk 就可以生成该渠道的 apk 了。
使用 Gradle 编译,可以一次生成多个渠道的 apk 了。
这里我用了不一样的签名,生成的 apk 签名肯定是不一样的。如何验证呢?
build 之后,会在 app/build/outputs/apk/ 目录生成多个渠道的 apk ,在 Terminal 栏使用如下命令查看 apk 的签名,
keytool -printcert -jarfile apk_path
apk_path 是 apk 的路径。
3 个渠道的 apk ,用的 jks 不一样,对应的结果是不一样的,说明已配置了不一样的签名。
3 个渠道的应用,包名不一样,可以安装到同一台机器上。对应的 app_name 、图标也不一样。