weijunfeng
3/18/2019 - 8:11 AM

多渠道打包

MultiChannelPackageTool
Android Multi channel package tool (安卓多渠道打包工具)

为什么需要这个工具
1、国内应用市场繁多,上线的apk应用需要知道自己在哪个渠道下载的;
2、简直是急速啊:5M的apk,1秒种能打300个;
3、因为是急速,可以做网页下载时动态打渠道包功能(如:分享apk给好友,好友下载打开apk后直接计算准确的分享量);
该工具的原理
利用的是Zip文件“可以添加comment(摘要)”的数据结构特点,在文件的末尾写入任意数据,而不用重新解压zip文件(apk文件就是zip文件格式);
所以该工具不需要对apk文件解压缩和重新签名即可完成多渠道自动打包,高效速度快,无兼容性问题;

另外美团的适配渠道包方案(不同的渠道嵌入不同的SDK):
美团Android自动化之旅—适配渠道包(Gradle flavor解决内嵌第三方SDK适配)(http://tech.meituan.com/mt-apk-adaptation.html)
与现有多渠道打包工具的对比
友盟(https://github.com/umeng/umeng-muti-channel-build-tool)
	打包:解压apk文件 -> 替换AndroidManifest.xml中的meta-data -> 压缩apk文件 -> 签名
	读取渠道号:直接通过Android的API读取meta-data
	特点:需要解压缩、压缩、重签名耗费时间较多,重签名会导致apk包在运行时有兼容性问题;
美团(http://tech.meituan.com/mt-apk-packaging.html)
	打包:解压apk文件 -> META-INF目录下创建一个以渠道号为文件名的空文件 -> 压缩apk文件
	读取渠道号:解压已安装的data/app/<package>.apk -> 读取以渠道号为文件名的空文件的文件名
	特点:比友盟高效点,只有解压缩和压缩,没有签名,兼容性也比较好,但是读取渠道号需要解压缩apk,速度比较慢;
我自己
	打包:直接写入渠道号到apk文件的末尾
	读取渠道号:直接读取data/app/<package>.apk文件末尾的渠道号
	特点:没有解压缩、压缩、重签名,没有兼容性问题,速度最快;写入的渠道号数据支持加密,安全可靠;
除了多渠道打包,我还能做什么?
由于速度极快,我还可以作为服务器端下载apk时动态写入“特定数据”,用户下载到apk后安装启动,读取“特定数据”完成特定的操作;
如:加好友功能,下载前写入用户ID,用户下载后启动apk,读取写入的用户ID,完成加好友操作,用户体验大大提升,没有断裂感;
当然,也可以写入JSON数据,想做什么就做什么;
如何使用
1、命令行使用说明:
用法:java -jar MCPTool.jar [-path] [arg] [-contents] [arg] [-password] [arg]
-path		APK文件路径
-outdir		输出路径(可选),默认输出到APK文件同一目录
-contents	写入内容集合,多个内容之间用“;”分割,如:googleplay;m360; 当没有“-contents”参数时输出已有文件中的content
-password	加密密钥(可选),长度8位以上,如果没有该参数,不加密
-version	显示版本号
例如:
写入:java -jar MCPTool.jar -path D:/test.apk -outdir ./ -contents googleplay;m360; -password 12345678
读取:java -jar MCPTool.jar -path D:/test.apk -password 12345678

2、Android代码中读取写入的渠道号:
导入MCPTool.jar中的MCPTool类,MCPTool.getChannelId(context, mcptoolPassword, defValue)读出写入的渠道号;

3、jenkins、hudson、ant使用说明:
请看MultiChannelPackageTool\build-ant\MCPTool\build.xml文件;

4、Windows下bat脚本运行说明:
拖拽文件即可完成多渠道打包:MultiChannelPackageTool\build-ant\MCPTool\MCPTool.bat;
拖拽文件检查渠道号是否写入成功:MultiChannelPackageTool\build-ant\MCPTool\MCPTool-check.bat;
上面2个bat文件中有密码,可以自行修改;
Android多渠道打包三种方式
2018年04月10日 11:19:11 来日未必方长 阅读数:2686
前言:
现在市场上很多app应用存在于各个不同的渠道,大大小小几百个,当我们想要在发布应用之后统计各个渠道的用户下载量,我们就要进行多渠道打包。
1
2
01.应用的打包签名
什么是打包?
打包就是根据签名和其他标识生成安装包。

签名是什么?
1.在android应用文件(apk)中保存的一个特别字符串

2.用来标识不同的应用开发者:开发者A,开发者B

3.一个应用开发者开发的多款应用使用同一个签名 
就好比是一个人写文章,签名就相当于作者的署名。 
如果两个应用都是一个开发者开发的,那么签名就是一样的。 
这个开发者,可以是个人,也可以是公司、团体。

为什么要用签名?
原因1:最简单直接的回答: 系统要求的。
Android系统要求每一个Android应用程序必须要经过数字签名才能够安装到系统中,也就是说如果一个Android应用程序没有经过数字签名,是没有办法安装到系统中的!

原因2:
不同程序员开发的应用包名可能会相同, 导致一个应用覆盖掉另一个应用。 
如果只有包名的概念,那么如果B应用与已经安装的A应用包名一样,那就实现覆盖。不合理! 
而事实上是装不上B的,它会提示,存在包名一致,但是签名不一样的。这就不会覆盖。

如何为APK签名?
如何签名就不用说了,这方面的博文数不胜数,相信看这篇文章的你也应该会。

在代码中得到应用的签名?(个人觉得没啥用)
public void getSingInfo() {
    try {
        PackageInfo packageInfo = getPackageManager().getPackageInfo(
                "应用包名", PackageManager.GET_SIGNATURES);
        Signature[] signs = packageInfo.signatures;
        Signature sign = signs[0];
        parseSignature(sign.toByteArray());
    } catch (Exception e) {
        e.printStackTrace();
    }
}
public void parseSignature(byte[] signature) {
    try {
        CertificateFactory certFactory = CertificateFactory
                .getInstance("X.509");
        X509Certificate cert = (X509Certificate) certFactory
                .generateCertificate(new ByteArrayInputStream(signature));
        String pubKey = cert.getPublicKey().toString();
        String signNumber = cert.getSerialNumber().toString();
        Log.e("TAG", "pubKey:" + pubKey);
        Log.e("TAG", "signNumber:" + signNumber);
    } catch (Exception e) {
        e.printStackTrace();
    }
}
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
注意问题:
现象: 
Android导出APK包时出现,编译调试时不会出现。 
错误信息: 
Error:(16) Error: “baidutieba_client_inavailable” is not translated in “en” (English) [MissingTranslation] 
Error:(63) Error: “baidutieba” is not translated in “en” (English) [MissingTranslation] 
Error:(67) Error: “share_to_baidutieba” is not translated in “en” (English) [MissingTranslation] 
错误截图:

这里写图片描述 
解决办法: 
resources 标签内增加两个属性即可:

<?xml version="1.0" encoding="utf-8" ?>  
<resources xmlns:tools="http://schemas.android.com/tools"  
  tools:ignore="MissingTranslation">  
</resources>
1
2
3
4
5
02.友盟的多渠道打包
说明:
1.什么是多渠道包?
渠道包就是要在安装包中添加渠道信息,也就是channel,对应不同的渠道,例如:小米市场、360市场、应用宝市场等

2.为什么要提供多渠道包?
我们要在安装包中添加不同的标识,应用在请求网络的时候携带渠道信息,方便后台做运营统计(这就是添加渠道信息的用处)。

3.实现多渠道打包的原理:
一般来讲,这个渠道的标识会放在AndroidManifest.xml的Application的一个Metadata中。然后就可以在java中通过API获取对应的数据了。

4.如何实现?
现在android渠道多种多样,其实渠道不仅仅局限于应用市场,一种推广方式也可以看做一个渠道,比如:通过人拉人的方式去推广,官网上推广,百度推广等。所以说渠道成千上万,为了推广,有时候一次也会打成千的安装包,那你半天或者一天啥都别干了,所以介绍几个大公司高效的打包方式,借鉴一下。

第一种:友盟就提供了多渠道打包的方式,可用于渠道统计等。 
现在Android的构建工具换成了gradle,通过gradle,简单配置后就可以实现自动打所有渠道包。

实现步骤:
1.按照umeng的要求,manifest文件中需要有

<meta-data
 android:name="UMENG_CHANNEL"
 android:value="${UMENG_CHANNEL_VALUE}" />
1
2
3
4
这段配置,value那里就是wandoujia,360之类的渠道名称,但是我们在这里不会去写渠道名,写的是一个占位符,后面gradle编译的时候会动态的替换掉它。

2、在module(一般也就是app)的build.gradle的android{}中添加如下内容:

productFlavors{
          wandoujia{
             manifestPlaceholders = [UMENG_CHANNEL_VALUE: "wandoujia"]
          }
          xiaomi{
             manifestPlaceholders=[UMENG_CHANNEL_VALUE: "xiaomi"]
          }
      }
1
2
3
4
5
6
7
8
9
productFlavors是android节点的一个自节点。你需要打什么渠道的包,就在这里按umeng的要求用渠道名给UMENG_CHANNEL_VALUE赋值。

3、优化1:上面只是两个渠道,如果有几十个渠道,都这样写,重复的东西太多,观察到每个渠道就是flavor的名称,所以修改如下:

productFlavors{
  wandoujia{
 
  }
  xiaomi{
 
  }
 }
 productFlavors.all { flavor ->
  flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
 }
1
2
3
4
5
6
7
8
9
10
11
12
4、优化2:上面经过签名打包后生成的apk的名称是有默认命名规则的,如:xxx-xiaomi-release.apk 但是我们想包含版本信息如:xxx-xiaomi-release-1.0.apk,所以最终打包脚本如下:

productFlavors{
    wandoujia{
 
    }
    xiaomi{
 
    }
 }
 productFlavors.all { flavor ->
    flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
 }
 applicationVariants.all { variant ->
    variant.outputs.each { output ->
        def outputFile = output.outputFile
        if (outputFile != null && outputFile.name.endsWith('.apk')) {
            def fileName = outputFile.name.replace(".apk", "-${defaultConfig.versionName}.apk")
            output.outputFile = new File(outputFile.parent, fileName)
        }
    }
 }
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
4.获取渠道 
在代码中我们可以通过读取mate-data信息来获取渠道,然后添加到请求参数中,获取方法如下:

private String getChannel() {
   try {
       PackageManager pm = getPackageManager();
       ApplicationInfo appInfo = pm.getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
       return appInfo.metaData.getString("UMENG_CHANNEL");
   } catch (PackageManager.NameNotFoundException ignored) {
   }
   return "";
}
1
2
3
4
5
6
7
8
9
10
5、执行签名打包 
这里写图片描述 
这时候你去app/build/outputs/apk中就能看到自动打好的渠道包了。

6、缺点: 
这样的打包方式效率比较低下,如果是几十个包还可以应付,打一个包快的话需要十几秒,慢的话需要几分钟不等,跟机器性能很有关系。

03、美团多渠道打包
原理:
把一个Android应用包当作zip文件包进行解压,然后发现在签名生成的目录下(META-INF)添加一个空文件不需要重新签名。利用这个机制,该文件的文件名就是渠道名。这种方式不需要重新签名等步骤,非常高效,但是貌似在Android7.0之后,Google为了增强签名的安全性,采用了新的签名规则,不是针对每个文件来进行数字编码,而是对zip包文件结构编码签名后产生一个唯一的数据叫做apk signing block。如果修改了zip文件的任何模块的内容,APK Signing Block都会发生改变,从而无法再绕过签名机制。

方法:
首先你需要去下载相关的工具: 
这里写图片描述

详细步骤:
1、将要打包的apk放到PythonTool中 
2、在PythonTool/info/channel.txt中写入需要的渠道,一个渠道占一行 
3、双击执行PythonTool/MultiChannelBuildTool.py文件(需要Python环境),就会生成渠道包 
4、获取渠道信息:将JavaUtil文件中的ChannelUtil.java拷贝到工程,调用ChannelUtil.getChannel即可获取渠道.

优缺点:
优点: 
这种打包方式速度非常快,900多个渠道不到一分钟就能打完

缺点: 
1、google现在已经修改了新的签名规则,若使用新的签名规则则无法使用(老的无所谓)。 
2、一些不法的渠道商很容易通过工具修改渠道,如果一个渠道商,通过网络劫持和篡改渠道的组合方式来获取暴利,对于程序开发者来说可能会存在着巨大的经济损失

04、360多渠道打包:
apk文件本质就是zip文件,利用zip文件“可以添加comment(摘要)”的数据结构特点,在文件的末尾写入任意数据,而不用重新解压zip文件,我们就可以将渠道信息写入摘要区

方法:
首先还是去下载相关工具: 
这里写图片描述

步骤:
1、将要写入渠道信息的apk放入MCPTool文件夹中 
2、修改MCPTool.bat批处理文件,更改渠道和密码(渠道信息为了安全需要加密)

3、将apk拖到MCPTool.bat上执行,将会生成渠道包

4、修改MCPTool-check.bat中的密码和MCPTool.bat中的密码一致

5、将渠道包拖到MCPTool-check.bat上执行,就可以检查渠道信息是否正确

6、获取渠道:将MCPTool.java添加到工程或者将MCPTool.jar导入工程,调用 
MCPTool.getChannelId(this,”12345678”,”“) 第一个参数为context,第二个是密码,第三个是默认值。

优缺点:
优点: 
1、5M的apk,1秒种能打300个 
2、在下载apk的同时,服务端可以写入一些信息,例如邀请码,分享信息等

缺点: 
渠道信息也是很容易修改,虽然可以加密,只是提高了修改的门槛

以上就是多渠道打包的一些方法,目前大部分公司常用的还是友盟的打包方式。