快速打渠道包

何为渠道包

每当发新版本时,Android客户端会被分发到各个应用市场,比如豌豆荚,360手机助手等。为了第三方统计平台以及自身服务端统计这些市场的效果(活跃数,下单数等),需要对各个不同的渠道市场所发的apk包用一些方法来唯一标识它们。 
此外,有一些渠道作为首发渠道,也需要单独打出不一样的包(一般是splash页面有对应渠道的首发标识)。

Maven式打包

Maven是一个软件项目管理和自动构建工具,配合使用android-maven-plugin插件,以及maven-resources-plugin插件可以较为自动化地生成渠道包。

在AndroidManifest.xml的节点中添加如下元素,用来定义渠道的来源

<!-- 使用Maven打包时会用具体的渠道号替换掉${channel} -->
<meta-data
        android:name="channel"
        android:value="${channel}" />

再在程序启动时读取渠道号:
PackageManager pm = context.getPackageManager();
            ApplicationInfo appInfo = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
            return appInfo.metaData.getString("channel");

1
2
3
4
5
6
7
8
9
10

1
2
3
4
5
6
7
8
9
10

缺点:每打一个包都要执行一遍构建过程,效率太低。

apktool式打包

apktool是一个逆向工程工具,可以用它解码并修改apk中的资源。接下来详细介绍如何使用apktool生成渠道包。

前期工作和用Maven打包一样,也需要在AndroidManifest.xml文件中定义元素,并在应用启动的时候读取清单文件中的渠道号。具体请参考前面的代码。

和Maven不一样的是,每次打包时不再需要重新构建项目。打包时,只需生成一个apk,然后在该apk的基础上生成其他渠道包即可。

小结:相当于Maven式的改进,不用每次都执行一次构建,节省了不少时间,但方式不太好,且也不够快。

Gradle 打渠道包

基本原理是利用Gradle的 manifest merger 功能 
这个功能的主要用途是能够在运行时替换AndroidManifest.xml里面的内容

第一步 在AndroidManifest.xml里配置meta-data
<meta-data
        android:name="UMENG_CHANNEL"
        android:value="${UMENG_CHANNEL_VALUE}" />
第二步 在模块的build.gradle文件的defaultConfig里加上PlaceHolder定义

android {
    ...

    defaultConfig {
        ...
        manifestPlaceholders = [ UMENG_CHANNEL_VALUE:"default_channel" ]
    }   
}

这里的作用有两个,一是声明UMENG_CHANNEL_VALUE是可替换值的PlaceHolder,二是为其设置默认值。


第三步 在模块的build.gradle文件里添加ProductFlavors配置
android {
    productFlavors {
        default_channel{}
        wandoujia{}
        _360{}
        yingyongbao{}
        xiaomi{}
        baidu{}
        huawei{}
        jifeng{}
    }
    productFlavors.all { flavor ->
        flavor.manifestPlaceholders = [ UMENG_CHANNEL_VALUE:name ]
    }
}    


第四步 一次生成所有渠道包

到工程目录下运行gradlew assembleRelease。
可以看到这次编译一共产生了对应productFlavors段的不同渠道包。

可以反编译每个apk,打开AndroidManifest.xml看看,发现友盟这一段的配置已经相应的被修改了。

<meta-data
        android:name="UMENG_CHANNEL"
        android:value="default_channel" />

还可以利用Gradle生成单独的渠道包  
如 gradlew assembleWandoujiaRelease  

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

META-INF 式打包

可以只修改已有apk的渠道标志 
快,批量,原理简单

使用APK注释字段保存渠道信息和MAGIC字节,从文件末尾读取渠道信息,读取速度快

打包速度快,可用于网站后台动态生成渠道包

packerNg 式打包

Android应用使用的APK文件就是一个带签名信息的ZIP文件,根据 ZIP文件格式规范,每个ZIP文件的最后都必须有一个叫 Central Directory Record 的部分,这个CDR的最后部分叫”end of central directory record”,这一部分包含一些元数据,它的末尾是ZIP文件的注释。注释包含Comment Length和File Comment两个字段,前者表示注释内容的长度,后者是注释的内容,正确修改这一部分不会对ZIP文件造成破坏,利用这个字段,我们可以添加一些自定义的数据,PackerNg项目就是在这里添加和读取渠道信息。

为了提高性能,避免读取整个文件,还需要在注释的最后加入几个MAGIC字节,这样从文件的最后开始,读取很少的几个字节就可以定位渠道名的位置。

http://www.woaipu.com/shops/zuzhuan/61406
http://www.znds.com/tv-967956-1-1.html
http://www.znds.com/tv-967958-1-1.html

http://www.woaipu.com/shops/zuzhuan/61406
http://www.znds.com/tv-967956-1-1.html
http://www.znds.com/tv-967958-1-1.html