Android多渠道打包实战
来源:互联网 发布:北海行知学校怎么样 编辑:程序博客网 时间:2024/05/16 10:22
什么是多渠道打包
BD为了统计营销推广的效果,需要在APK里写入推广渠道,去弄清用户、广告销售是来源于哪个渠道,如是来源于应用宝、百度手机助手这样的应用商店,还是广点通、百度联盟这样的广告平台,以便后续分成结算。因此,开发人员需要为BD提供不同渠道所对应的apk文件。而生成这些不同渠道所对应的APK文件就叫做多渠道打包。
多渠道打包的发展史
从发展历程来看,多渠道打包大约经历了这样几个阶段:
第一阶段:用脚本直接生成渠道apk
在Android开发早期,一般是用eclipse开发,用ant来构建。先创建一个模板文件,如AndroidManifest_t.xml。该模板文件里包含一个渠道的特征串,如“{umeng_channel}”,然后用python之类的脚本替换到渠道特征串,用ant重新构建和签名。现在回想一下,从2011年底到2013年,我竟然在这种方式下使用了2年多 :(
这种方式和目前通过gradle productFlavors的manifestPlaceholders占位符打包实现是基本一致的,只是它又进了一步,把脚本功能也给你实现了。
这种方法每次都需要重新构建和签名,很耗时间。在渠道比较少的时候,还可以接受;当渠道多了,输出几百个渠道包一般都得花费好几个小时,这是无法忍受的。
第二阶段:反编译再签名
通过对第一阶段方法的介绍,我们发现每次都用ant构建项目是最费时的,也不是完全必要的。因此,我们又想出一招来改进:用ApkTool先反编译已apk,然后用脚本替换掉AndroidManifest.xml中的渠道,最后再用jarsigner工具重新签名即可。
这种方法省去了之前ant构建工程的时间,效率得到大大提高。
第三阶段:添加额外信息
这是目前所处的阶段。在这一阶段,目前市面主要有2个做法:
- 在APK的META-INF里添加一个渠道名的空文件,这种方法最早应该是从美团流行开来的。详情抽着:美团Android自动化之旅—生成渠道包
- 利用zip文件特点,使用APK注释字段保存渠道信息。目前在github上有开源的工具和详细介绍:下一代Android打包工具
这种方式既不用重新构建工程,也不用重新签名,是目前效率最高的打包方式。
实战
我司目前使用的是:APK注释法。
随着商业的发展,推广渠道越来越多样化,有些渠道已经不复存在,但新的渠道又不断地冒出来,以前固定打包渠道方式导致开发与BD沟通不畅,因此经过讨论,我们采取动态打包方式:给BD提供一个网址,BD自行输入渠道号后生成相应的apk,这样达到BD和开发就进一步“解耦”。
我们的内部网站是用PHP实现的,主要是通过ZipArchive添加相应的API。在服务端生成渠道包的主要代码如下:
copy("uploads/myapp.apk","uploads/myapp_{$channel}.apk");$zip = new ZipArchive;$res = $zip->open("uploads/myapp_{$channel}.apk"); if ($res === TRUE) { $zip->setArchiveComment(base64_encode($channel)); $zip->close(); ...
客户端获取渠道的主要代码,请参考Read a zip file comment with Java
String apkPath=context.getPackageCodePath();//获取安装后APK所在路径,普通应用在data/app下String channel=extractZipChannel(apkPath);/* *以下2个方法实现从APK文件中获取注释内容。 */public static String extractZipChannel(String filename) { String retStr = null; try { File file = new File(filename); int fileLen = (int) file.length(); FileInputStream in = new FileInputStream(file); /* The whole ZIP comment (including the magic byte sequence) * MUST fit in the buffer * otherwise, the comment will not be recognized correctly * * You can safely increase the buffer size if you like */ byte[] buffer = new byte[Math.min(fileLen, 8192)]; int len; in.skip(fileLen - buffer.length); if ((len = in.read(buffer)) > 0) { retStr = getZipCommentFromBuffer(buffer, len); } in.close(); } catch (Exception e) { e.printStackTrace(); } return retStr; } /* * magicDirEnd[0x50,0x4b,0x05,0x06]: End of central directory signature. * There are 22 bytes between magicDirEnd and the start of the comment, * and the last 2 bytes are the length of the comment. */ static String getZipCommentFromBuffer(byte[] buffer, int len) { byte[] magicDirEnd = {0x50, 0x4b, 0x05, 0x06}; int buffLen = Math.min(buffer.length, len); //Check the buffer from the end for (int i = buffLen - magicDirEnd.length - 22; i >= 0; i--) { boolean isMagicStart = true; for (int k = 0; k < magicDirEnd.length; k++) { if (buffer[i + k] != magicDirEnd[k]) { isMagicStart = false; break; } } if (isMagicStart) { //Magic Start found! int commentLen = buffer[i + 20] + buffer[i + 21] * 256; int realLen = buffLen - i - 22; String comment = new String(buffer, i + 22, Math.min(commentLen, realLen)); return comment; } } return null; }
关于ZIP文件格式请参考ZIP文件格式分析。下图是该文中对zip文件目录结束标识部分的说明:
另外需要说明一点的是,这种方式不能采用最新的APK Signature Scheme v2,您可以在build.gradle中禁用v2签名,即在signingConfigs中相应地添加v2SigningEnabled false
android { ... defaultConfig { ... } signingConfigs { release { storeFile file("myreleasekey.keystore") storePassword "password" keyAlias "MyReleaseKey" keyPassword "password" v2SigningEnabled false } } }
关于APK Signature Scheme v2,请参考android开发者官网介绍:Android 7.0 开发者版本
- Android多渠道打包实战
- Gradle实战:Android多渠道打包方案汇总
- Gradle实战:Android多渠道打包方案汇总
- Android多渠道打包(一):基础多渠道打包
- Android多渠道打包(四):360多渠道打包
- Android多渠道打包(五):360多渠道打包+
- android 多渠道自动打包
- android apk多渠道打包
- Android多渠道打包APK
- android 多渠道打包
- Android 多渠道自动打包
- android应用多渠道打包
- Android Ant 多渠道打包
- Android多渠道Ant打包
- android多渠道打包
- Android多渠道打包工具
- android ant 多渠道打包
- Android studio 多渠道打包
- 【设计模式】面向对象原则
- 微信小程序开发过程中总结的注意事项
- 包围球的计算
- <感受2>
- 最容易懂得红黑树
- Android多渠道打包实战
- 读《Redis入门指南》2
- iOS可能用到的小知识
- poj 3259 worm-holes spfa判断负权回路
- mac上编译boost
- synchronized关键字总结
- 探索并发编程(六)------Java多线程性能优化
- iOS App 上架流程图文教程
- this.class.getClassLoader()怎么理解?