这是我参与8月更文挑战的第5天,活动详情查看:8月更文挑战
Android 如何几秒生成一百个渠道包
众所周知,因为国内Android应用分发市场的现状,我们在发布APP时,一般需要生成多个渠道包,上传到不同的应用市场。这些渠道包需要包含不同的渠道信息,在APP和后台交互或者数据上报时,会带上各自的渠道信息。这样,我们就能统计到每个分发市场的下载数、用户数等关键数据。
一、普通的多渠道打包
先讲讲普通的多渠道打包
在用Eclipse的年代,我们会在AndroidManifest.xml文件中增加渠道的配置,每次打包时就会切换下渠道号再次打包。代码如下
<meta-data
android:name="APP_CHANNEL"
android:value="360" />
如需要切换百度渠道,则再次更改为
<meta-data
android:name="APP_CHANNEL"
android:value="baidu" />
如此一来,重复的工作量大大增加。于是就有了AndroidStudio上的多渠道打包。
- 在AndroidManifest.xml文件中,还是依旧的meta-data标签,只是属性改为动态的属性。如下
<meta-data
android:name="APP_CHANNEL"
android:value="${APP_CHANNEL_VALUE}" />
- 在build.gradle中的android标签内增加如下代码,其中APP_CHANNEL_VALUE后面的值就是渠道号的值
productFlavors {
xiaomi {
manifestPlaceholders = [APP_CHANNEL_VALUE: "xiaomi"]
}
baidu {
manifestPlaceholders = [APP_CHANNEL_VALUE: "baidu"]
}
}
如提示:All flavors must now belong to a named flavor dimension. 此时还需要在defaultConfig的标签内添加flavorDimensions属性,整体的代码如下:
defaultConfig {
applicationId "com.channel.project"
minSdkVersion 19
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
flavorDimensions "1" //一般与versionCode相同
}
- 在代码中获取渠道号的方法
/**
* 获取项目的渠道号
*
* @return
*/
public static String getChannel(Context context) {
ApplicationInfo ai = null;
try {
ai = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
return bundle.getString("APP_CHANNEL");
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return "";
}
- 如下,在我们使用build-Generate Signed Bundle or APK时,点击Next,就会出现以下界面,全选即可,打包就在默默的进行了。
- 细心的你会发现,如果项目较大或者渠道较多,会消耗大量的时间,怎么解决这个问题呢,看看walle的解决方案。
二、多渠道打包walle
带着上个的问题来探寻快速打包的秘密。
一、大概原理
为了方便理解,我把原理总结了一下,android的apk是基于zip格式压缩的,walle在zip中插入了一个区域,这个区域叫做apk sign block,所以快速打包的根本原因在于仅改变了apk sign block区域的内容,在运行时读取apk sign block中的内容。
详细原理大家有兴趣的去看看相关链接。 www.jianshu.com/p/604ffd019… 快速打包的工具当然不止walle一个,该篇仅仅是对walle实战的记录。
二、walle实战
官方github传送门:github.com/Meituan-Dia… 推荐该官方链接,更权威更详细。当然有些坑可以看issues。
- 引入配置文件 (注意:引入该快速打包方式前,要将以前的普通打包方式代码移除干净) 在位于项目的根目录 build.gradle 文件中添加Walle Gradle插件的依赖, 如下:
buildscript {
dependencies {
classpath 'com.meituan.android.walle:plugin:1.1.6'
}
}
并在当前App的 build.gradle 文件中apply这个插件,并添加上用于读取渠道号的AAR
apply plugin: 'walle'
dependencies {
compile 'com.meituan.android.walle:library:1.1.6'
}
并在当前App的 build.gradle 文件添加如下代码
walle {
// 指定渠道包的输出路径
apkOutputFolder = new File("${project.buildDir}/outputs/channels")
// 定制渠道包的APK的文件名称
apkFileNameFormat = 'app_${channel}-v${versionName}-${versionCode}-${buildTime}.apk'
// 渠道配置文件appName
channelFile = new File("${project.getProjectDir()}/channel")
}
- 在当前app的根目录创建channel文件,讲需要打包的渠道号依次写入,eg
meituan # 美团
samsungapps #三星
hiapk
anzhi
xiaomi # 小米
- 在代码中获取渠道号
WalleChannelReader.getChannel(context.getApplicationContext())
如需在debug时的默认渠道号
WalleChannelReader.getChannel(context.getApplicationContext(),"defaultChannel")
- 如需指定多个key-value作为渠道 1)添加channel_json,内容为
{
"defaultExtraInfo": {
"Channel_Name_1": "default",
"Channel_Name_2": "default"
},
"channelInfoList": [
{
"channel": "xiaomi",
"extraInfo": {
"Channel_Name_1": "xiaomi_value_1",
"Channel_Name_2": "xiaomi_value_2"
}
},
{
"channel": "360",
"extraInfo": {
"Channel_Name_1": "360_value_1",
"Channel_Name_2": "360_value_2"
}
}
]
}
- 修改当前App的 build.gradle-walle标签
walle {
// 指定渠道包的输出路径
apkOutputFolder = new File("${project.buildDir}/outputs/channels")
// 定制渠道包的APK的文件名称
apkFileNameFormat = 'app_${channel}-v${versionName}-${versionCode}-${buildTime}.apk'
// 渠道配置文件appName
configFile = new File("${project.getProjectDir()}/channel_json")
// channelFile = new File("${project.getProjectDir()}/channel")
}
- 对应的渠道信息获取方式如下
ChannelInfo channelInfo= WalleChannelReader.getChannelInfo(this.getApplicationContext());
if (channelInfo != null) {
String channel = channelInfo.getChannel();
Map<String, String> extraInfo = channelInfo.getExtraInfo();
}
// 或者也可以直接根据key获取
String value1 = WalleChannelReader.get(context, "Channel_Name_1");
String value2 = WalleChannelReader.get(context, "Channel_Name_2");
请详细注意debug时为null的情况,debug时如何使用渠道呢?了解了再更新
/**
* 获取项目的渠道号
*
* @return
*/
public static String getChannel(Context context) {
String value = WalleChannelReader.get(context, "Channel_Name_1");
return value == null ? "defaultValue" : value;
}
- 生成渠道包,在terminal中使用命令,生成渠道apk就在app-outputs-channels目录下
./gradlew clean assembleReleaseChannels
注:整个过程中出现Error:Plugin requires 'APK Signature Scheme v2 Enabled' for release. 1)请详细检查配置文件,确保正确性。 2)升级Gradle Plugin版本,大于2.2.0即可,如果手工设置了v2SigningEnabled=false,需要去掉。