盒子
盒子
文章目录
  1. 前言
  2. 正文
    1. 解决
      1. 最基本方式
      2. 优化方式
    2. 原理

Andorid多渠道打包

前言

2016刚刚过去,自己写博客是在2016.03.04,其实这个日子很特别,也很有戏剧色彩(内幕我现在是不会告诉你们滴,猜去吧!)。浏览了下自己去年的成果,文章数量还是很可观的,起初的一个月4篇到后面的一个月1篇。现在自己也要工作,不再像原来在学校那么多时间,从最近的博客更新来看,发现自己最近偷懒了哦(偷懒确实很爽)!新的一年给我一击警钟,我不能荒废我的博客,我要重拾我的初衷。在此借助这篇文章立下证据

新的一年新的开始,一步一个脚印迎接2017


正文

感谢倾听我的感慨,下面正式进入主题。关于这次的多渠道打包也是在工作中才认识有这一回事,原来在学校更本不会接触到这些,社会是最好的老师。对于每一个App都要发布到不同的平台,因此就有了许多的渠道(360、baidu、xiaomi、91、oppo等),而公司为了更好的追踪用户对产品的使用情况,要对不同渠道下载的用户进行统计。至于统计现在大多数都是使用友盟。如何统计这里就不多说了,可以自行看官方文档。所以对于不同的渠道我们要分别打包,当然这也是Android多平台的缘故,相对于IOS却没有这么一回事。现在渠道有900多个,一般打一次包就要3~4分钟,像我公司要针对66个渠道进行打包。如果按部就班来那就要3~4个小时了(哇好爽啊,半天工作时间就过去了,偷懒成功)这样工作效率完全被这种无意义的东西浪费了。如果把这些时间用来撩妹终身大事就不愁了(嘻嘻)。

解决

最基本方式

最基本的设置渠道的方式是在AndroidManifest.xml文件中定义<meta-data>元素

1
2
3
4
5
6
<meta-data
android:name="UMENG_CHANNEL"
android:value="Channel_ID" />
<meta-data
android:name="UMENG_CHANNEL"
android:value="web" />

这里是使用了友盟统计, 上面的web就是渠道名,不同渠道对应不同的值。对于渠道少的可以直接在build.gradle中进行设置productFlavors

1
2
3
4
5
6
7
8
9
10
11
12
13
14
productFlavors {
xiaomi {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "xiaomi"]
}
_360 {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "_360"]
}
baidu {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "baidu"]
}
wandoujia {
manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
}
}

或者统一修改

1
2
3
4
5
6
7
8
9
productFlavors {
xiaomi {}
_360 {}
baidu {}
wandoujia {}
}
productFlavors.all {
flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}

这是针对渠道少的,也是最基本的方式。而对于渠道过多的,例如我现在遇到的60多个,又该如何解决呢?

优化方式

这里借助第三方库packer-ng,进行快速打包,它只需执行一次正常的打包操作,剩下的渠道每个以1秒以内的速度进行打包。速度是不是非常可观呢(麻麻再也不用担心我的效率了)。

首先在项目的根目录的bulid.gradle中进行设置

1
2
3
dependencies {
classpath 'com.mcxiaoke.gradle:packer-ng:1.0.8'
}

再切换到app下的build.gradle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
apply plugin: 'packer'

signingConfigs {
release {
//省略相关配置
....
//如果你的gradle版本超过2.14.1
//gradle plugin版本超过2.2.0 就要设置该项
//为了禁用默认的v2版签名模式
v2SigningEnabled false
}
}

dependencies {
compile 'com.mcxiaoke.gradle:packer-helper:1.0.8'
}

packer {
// 指定渠道打包输出目录
archiveOutput = file(new File(project.rootProject.buildDir.path, "cyzs_apks"))
// 指定渠道打包输出文件名格式
// 默认是 `${appPkg}-${flavorName}-${buildType}-v${versionName}-${versionCode}`
archiveNameFormat = 'cyzs.${versionName}.${flavorName}'
// 是否检查Gradle配置中的signingConfig,默认不检查
// checkSigningConfig = false
// 是否检查Gradle配置中的zipAlignEnabled,默认不检查
// checkZipAlign = false
}

这是关于gradle方面的,既然现在不在AndroidManifes.xml中进行设置渠道,就要另寻它法,这里在项目的根目录创建marktes.txt文本,文本中的内容就是所需的渠道,格式如下

1
2
3
4
5
6
7
8
9
10
11
12
13
web
360
Tencent
baidu
91
Anzhuo
anzhi
Wandou
ppzhushou
Xiaomi
zhihuiyun
oppo
vivo

既然现在解决了渠道的定义,那么下一步就是如何在项目中进行读取设置的渠道了,前面我们已经继承了相关的库,所以读取也非常简单

1
channel = PackerNg.getMarket(context);

这样就拿到了渠道名,后续的操作就可以进行相应的操作了。根据自己的需求来,一般都是将渠道上传到友盟与服务器。

最后剩下的就是执行打包了,在命令行执行

1
./gradlew -Pmarket=markets.txt clean apkRelease

-Pmarket是为了指定渠道存放的路径,根目录中直接为markets.txtclean是为了清除原来输出目录中的apkapk[buildType]是标明打什么包。这里是release。还有一个简洁的方式,可以省略-Pmarket=markets.txt。如此需要在gradle.properites中进行配置

1
market=markets.txt

再执行

1
./gradlew clean apkRelease

好了,大功告成,再等3~4分钟就完美收工了。最后打好的apk会在上面定义的路径中,例如对于上面所定义的路径:项目根目录/build/cyzs_apks

apks

原理

Android应用的APK都是一个zip文件,而zip文件规定在每一个文件末尾都有一个叫Central Directory Record的部分,它包含一些数据,它的末尾是apk的注释,所以可以借助这一点修改这一部分的数据,向其中加入我们所需的渠道名,但这却不破坏apk文件,所以根本要解决的就是在项目中对这些数据进行读与写。这就是最终的解决思路。

当然还有不借助gradle的,直接使用命令行打包,分别有javapython脚本。今天时间有点晚就不多说了,如需了解的可以后续再单独讨论。

2017第一篇文章完美收工

支持一下
赞赏是一门艺术