Android打包之多版本、多环境、多渠道
在平时的Android开发中,我们经常会遇到在不同网络环境(比如:开发环境、测试环境)之间的切换、一次打多个渠道包等需求,如何优雅的管理网络环境的配置?如何快速的打出多个渠道包?这是一个值得研究的问题。
如果每一次在不同网络环境间切换,都需要更改代码,然而重新打包,那未免有点低效。下面是我的实践探索,看网上很多人都是根据buildType来切换网络环境,感觉有点不好,因为网络环境可能很多种,而buildType我们一般是2种,而且,不同网络环境的包最好能同时安装在手机上,以便我们调试。最好,我一看这个包的名称和图标,就能知道这是什么环境的包。
一、概述
1.多版本
基于buildTypes
(1)debug:调试版本,无混淆
(2)release:发布版本,有混淆、压缩
2.多环境
基于productFlavors
(1)develop:开发环境,开发和自测时使用
(2)check:测试环境,克隆一份生产环境的配置,在这里测试通 过后,再发布到生产环境。
之所以没命名为test是因为在gradle编译时:ProductFlavor names cannot start with ‘test’
(3)product:生产环境,正式提供服务的。
二、示例
1、配置build.gradle
(1) 在位于项目的根目录 build.gradle 文件中添加Walle Gradle插件的依赖, 如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.admin.versiondemo"
minSdkVersion 15
targetSdkVersion 28
versionCode 1
versionName "1.0"
flavorDimensions "versionCode"//多环境打包设置
multiDexEnabled true
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
ndk {
// 设置支持的SO库架构(第三方腾讯bug上传含有多个SO库架构)
abiFilters 'armeabi', 'x86', 'armeabi-v7a'
//, 'x86', 'armeabi-v7a', 'x86_64', 'arm64-v8a'
}
}
//*******************打包设置开始
//自定义生成的apk的地址及名称
def apkName;
signingConfigs {
release {
storeFile file('version.jks')
storePassword '123456'
keyAlias 'version'
keyPassword '123456'
}
}
buildTypes {
debug {
minifyEnabled false//混淆
apkName = "version.apk"
signingConfig signingConfigs.release
}
release {
// 不显示Log
buildConfigField "boolean", "LOG_DEBUG", "false"
//混淆
minifyEnabled true
//Zipalign优化
zipAlignEnabled true
// 移除无用的resource文件
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
apkName = "version.apk"
signingConfig signingConfigs.release
}
}
android.applicationVariants.all { variant ->
variant.outputs.all {
if (outputFileName.endsWith('.apk')) {
//这里使用之前定义apk文件名称
outputFileName = apkName
}
}
}
//*******************打包设置结束
//*******************多环境打包设置开始
productFlavors {
//开发环境
develop {
buildConfigField "int", "ENV_TYPE", "1"
applicationId 'com.admin.versiondemo'
manifestPlaceholders = [
app_name: "开发环境",
app_icon: "@drawable/icon_develop"
]
}
//测试环境
check {
buildConfigField "int", "ENV_TYPE", "2"
applicationId 'com.admin.versiondemo'
manifestPlaceholders = [
app_name: "测试环境",
app_icon: "@drawable/icon_check"
]
}
//生产环境
product {
buildConfigField "int", "ENV_TYPE", "3"
applicationId 'com.admin.versiondemo'
manifestPlaceholders = [
app_name: "生产环境",
app_icon: "@drawable/icon_product"
]
}
}
//*******************多环境打包设置结束
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
(2) 这里,我根据不同的环境生成了不同包名的apk,方便在手机上同时安装多个环境的应用。为了让gradle动态更改apk的名称和图标,我们需要在manifest文件中使用 a p p i c o n 、 {app_icon}、 appicon、{app_name}等占位符
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.admin.versiondemo">
<application
android:name=".App"
android:allowBackup="true"
android:icon="${app_icon}"
android:label="${app_name}"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
这里我们最好定义一个常量类区分这些环境的类型:
public class EnvType {
public static final int DEVELOP = 1;//开发环境
public static final int CHECK = 2;//测试环境
public static final int PRODUCT = 3;//正式环境
}
2、打包多环境
这里我们直接执行assemble命令,打包所有的buildTypeproductFlavors
或者使用命令行也可以:
gradle assemble
执行结果:26秒搞定6个包:2个版本3个环境
这里我们可以看到debug包都是1.6M,而release包都是1.1M,显然,我们的混淆和压缩配置是生效了
我们分别安装3个环境的包到自己的手机上:
看三个包的名称和图标都不一样,显然我们之前在manifest文件中配置的占位符生效了。
逻辑代码
public class App extends Application {
//多环境打包路径
public static int envType = BuildConfig.ENV_TYPE;//多环境打包标志 1:开发环境 2:测试环境3:生产环境
public static String MY_STR = "";
@Override
public void onCreate() {
super.onCreate();
//初始化多环境打包
initMultiPackage();
}
/**
* 初始化多环境打包
*/
private void initMultiPackage() {
switch (envType) {
case EnvType.DEVELOP://开发环境(
MY_STR = "开发环境";
break;
case EnvType.CHECK://测试环境
MY_STR = "测试环境";
break;
case EnvType.PRODUCT://生产环境
MY_STR = "生产环境";
break;
}
}
}
Activity
public class MainActivity extends AppCompatActivity {
private TextView tvMultiPackage;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
tvMultiPackage = findViewById(R.id.tv_main_multi_package);
tvMultiPackage.setText(App.MY_STR);
}
}