默认
发表评论 3
想开发IM:买成品怕坑?租第3方怕贵?找开源自已撸?尽量别走弯路了... 找站长给点建议
Android版微信安装包“减肥”实战记录

前言


用户抱怨安装包越来越大?印度友人反馈装不上微信?做一个有节操的安装包,我们希望它越小越好,并且确保用户都能安装的上。Android的安装包,简单来说就是一个压缩包,我们需要先了解它后才能深入优化,请继续往下看。

相关文章


本文的iOS姊妹篇:《移动端IM实践:iOS版微信界面卡顿监测方案
资源混淆工具下载:《微信团队原创Android资源混淆工具:AndResGuard
资源混淆工具原理:《微信团队原创资源混淆工具:让你的APK立减1M

先来看看APK包的编译过程


以ant、gradle等方式编译生成安装包,通常包含以下几个步骤:

APK编译过程.jpg

但是对于多library的结构下,ant与gradle的并行度并不足够。当前微信已经切换到Facebook的开源编译工具buck(相关介绍请见http://facebook.github.io/buck/),编译速度得到了大大提升。

在buck的基础上我们主要做了以下两个工作:

  • EclipseToBuck,开发者无须关心buck脚本的编写,buck脚本使用代码自动生成
  • 微信使用多library结构,每次编译后监控每个模块的线性内存、方法数、资源大小。

QQ20160310-0.png

QQ20160310-1.png

开始动手“减肥”了


1安装包监控机制


我们做安装包优化,首先要对我们安装包每一部分有一个详细的了解,知道安装包大在什么地方,与上一版本有着怎么样的变化。

所以我们首先实现了一个安装包检测工具:

  • 1. 监控每个dex方法数的变更情况;
  • 2. 监控每个模块线性内存的变化情况;
  • 3. 没有alpha通道的png图,可压缩成jpg减少体积;
  • 4. 超过一定数值的大文件,特别是图片资源可采用有损压缩;
  • 5. 监控安装包的大小、文件数变化;
  • 6. 监控新增文件、减少文件,文件大小发生变化的情况;

现时微信的安装包监控包括两个维度,一是每日的监控,采用的是最后一个包与昨日的最后一个包对比;二是版本之间的对比,发布前需要用待上线版本与线上版本对比。我们希望若发现问题,能立刻警报,提交到bug系统。

2删除无用资源


在产品的大锤下,每个模块不修改个三五十次,都不好意思说自己是微信的开发。在不停的迭代中,或多或少会出现无用的资源,包括但不限于xml、png、id、string。
查找无用资源主要使用lint的UnusedResources以及UnusedIds两个检查规则,但是针对多library结构,官方的lint在某些方面不符合我们的要求,所以我们修改了一些地方。

对于使用gradle的童鞋,可以采用:
android {
    ...
    buildTypes {
        release {
            minifyEnabled true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

3图片资源的优化


.png、.9.png、.jpg、.gif资源是每一个安装包永远的痛,追求美感的设计师希望每个像素都是完美的。优化时主要关注以下几点:

  • 1. 对于体积特别大(超过50k)的图片资源可以考虑有损压缩,jpg采用优图压缩,png尝试采用pngquant压缩,输出视觉判断是否可行;
  • 2. 对assets中的图片资源也使用aapt的crunch做图片预处理;
  • 3. crunch有可能会使图片变大,在这种情况,我们可以替换成原图。需要注意的是对于.9.png,由于crunch过程中去除了黑边,所以不能替换;
  • 4. 对于没有透明区域的png图片,可以转成jpg格式。

4字符串编码


为了节省空间,resources.arsc中的会有一个去重过的字符串资源池(相同的两个字符串其实用的是同一份),每个String使用偏移值来获取资源池中的数值。ResourceTable的编码对于resources.arsc的体积有很大影响。

从Android 2.2 API Level8开始APK文件的资源resources.arsc的编码有了小幅的改变,过去使用的是UTF-16编码方式被转换成了UTF-8编码。这样的好处就是处理纯英文等直接通过ascii存储语言的国家资源文件将会更小,而对于中文、日文这些国家的资源文件有可能会变大。
bool getUTF16StringsOption() {       
     return mWantUTF16 || !isMinSdkAtLeast(SDK_FROYO);
}

当然如果你发现使用UTF-8后resources.arsc反而变大,你可以强制使用UTF-16编码。只需要在aapt中指定--utf16参数,也就是指定mWantUTF16为true(下面的注释似乎跟代码有出入)。
    " --utf16\n"
    " changes default encoding for resources to UTF-16.  Only useful when API\n"
    " level is set to 7 or higher where the default encoding is UTF-8.\n"

微信5.2.1把minSdkVersion更改到8,使用utf8编码后,resources.arsc减少了将近1M。

5指定文件的压缩方式与7zip压缩


安装包是一个压缩文件,我们可以指定里面的文件采用哪种压缩方式。假若我们输入下面的命令:
aapt l <file_path.apk> 
参数:
-v:会以table的形式输出目录,table的表目有:Length、Method、Size、Ratio、Date、Time、CRC-32、Name。

其中Method表示压缩形式,有:Deflate及Stored两种,即该Zip目录采用的算法是压缩模式还是存储模式;可以看出resources.arsc、*.png采用存储模式,而其它采用压缩模式。

有时候我们为了把某个数据文件不压缩,而把它的后缀名改成png(其实可以指定appt参数 -0 )。其实aapt对于某些压缩率不会太高的文件都默认使用了Stored模式。具体如下:
/* these formats are already compressed, or don't compress well */
static const char* kNoCompressExt[] = {".jpg", ".jpeg", ".png", ".gif",    ".wav", ".mp2", ".mp3", ".ogg", ".aac",    ".mpg", ".mpeg", ".mid", ".midi", ".smf", ".jet",    ".rtttl", ".imy", ".xmf", ".mp4", ".m4a",    ".m4v", ".3gp", ".3gpp", ".3g2", ".3gpp2",    ".amr", ".awb", ".wma", ".wmv"};

文件如果采用Deflate方式存储,意味着通过AssetManager读取时需要解压,耗费的时间与文件的压缩比成比例。但大家记得这里面有一个坑,在Android 2.3以前的任何压缩的资源的原始大小超过1M,AssetManger读取时会抛出异常。这里面需要关注的地方有:

  • 1. 对.png、.jpg强制压缩,但是的确普遍压缩率在3%-5%,收益不是特别高;
  • 2. 假若你的resources.arsc小于1M,可以对它进行压缩,这边可压缩50-70%。需要注意的是,如果你的resources.arsc是压缩的,程序需要把它读到内存,也就是会增大运行内存;
  • 3. 对于安装包中的jar可以指定不压缩,其实二次压缩的压缩率非常低;

此外,7z压缩算法号称优化了字典,完全兼容zip,使用7zip的最大压缩模式比传统zip方式的确有所提升,但是这里需要注意两个问题:

  • 上文kNoCompressExt说到的流媒体文件,是通过mediaplay直接拿文件句柄(没有像assetmanager会先解压文件,要求文件是seekable)也不能压缩。
  • 那么说一般来说只有.jpg、.jpeg、.png、.gif可以压缩,对于不需要兼容低版本或者resources.arsc小于1M的apk,可选择压缩resources.arsc。

6NDK编译后的So库


  • C++运行时库统一使用stlport_shared:
    之前微信中的C++运行库大多使用静态编译方式,使用stlport_shared方式可减小APK包大小,相当于把大家公有的代码提取出来放一份,减少冗余。同时也会节省一点内存,加载so的时候动态库只会加载一次,静态库则随着so的加载被加载多份内存映像。
  • 把公用的C++模块抽成功能库:
    其实与上面的思路是一致的,主要为了减少冗余模块。大家都用到的一些基础功能,应该抽成基础模块。

7语言包动态加载


由于微信是一个国际化软件,我们在String中添加了20多种语言支持。这也导致我们的resources.arsc有5M多之巨,尝试过假如只留下默认的中文,resources.arsc可减少超过一半。事实上,大多数的语言我们并没有使用到,这里提到的一个思路是动态下发语言包,程序中继承Resource实现getString方式读取即可。

假若你的apk并不要求联网,要求用户动态下发语言包似乎不work。这里在研究buck编译的时候看到另外一个思路,即把大部分的语言二进制存放在assets。这个由于是普通数据文件,采用Deflate压缩方式,会有比较大的压缩率(与数据存储方式也有关系)。

8资源混淆


我们常常用proguard来混淆代码,那我们有没有想过资源是否可以混淆?而混淆资源能带来什么样的好处?

  • 1. 比较酷,让反编译的人更加难受一下。面对一大堆以a,b,c,d命名的png、xml;
  • 2. 由于resources.arsc需要记录id与name的键值对,资源混淆对减少安装包体积也有帮助。具体数值与编码方式、id数量、平均减少命名长度有关(其实可以自己估量一下)。

微信的资源混淆工具不依赖源码,只要输入一个apk就能得到一个混淆之后的apk,大家有兴趣的话,可以后续单独来讲。通过资源混淆微信大约能减少1M左右的大小,效果如下:

微信图片混淆结果.jpg

9持续交付


持续交互的终极目标就是让使用某个功能的人才会真正去下载某个模块,这首先需要我们代码结构的支持,即模块化以及支持动态加载。微信对gpserver、打飞机等功能试用动态加载方式。其实这块的核心思想就是将一些边缘的,不常用的功能,都尽量采用这种方式加载。但需要与产品大大们激烈PK,用户至上嘛。
记住,砍功能永远是减少安装包的第一法宝!

安装包能否正常使用


这里讨论第二个主要问题,如何确保我们的安装包用户都能安装的上,特别是2.3以下的爷们(希望有不需要考虑它们的一天)。


1Dex的65536高压线


原因你懂得,超过请减少方法数,或自行拆多dex。其实在这里,我们这边有一点积累,但不在这篇文章的讨论范围。具体可参考km中的一些文章:
计算某个dex的方法总数,可使用:
function dex-method-count() {
  cat $1 | head -c 92 | tail -c 4 | hexdump -e '1/4 "%d\n"'
}

想看到所有的方法,用dexdump吧。

2任何压缩的资源的原始大小不能超过1M


具体参考减少安装包大小tips中的第五点。

3线性内存限制


其实这个往往才是决定安装包是否能安装的上的阿喀琉斯之踵(用完这个名词,顿时高大上)。关于线性内存的限制,可参考文章:https://www.facebook.com/notes/f ... d/10151345597798920

简单来说就是在dexopt过程中,系统限制一个5-16M的线性内存,如果在读取dex数据过程中超过了这块内存,就会出现dexopt失败。由于dalvik加载系统模块时需要占用部分内存,facebook的推荐值我们自身dex的最大值是4M,但我们发现在某些2.3的机器超过3.5M之后依然会dexopt失败。微信计算线性内存使用的是buck中asm-debug-all中提供的方法,计算class中会被dexopt中会读入线性内存的总大小:

微信编译so1.jpg
(buck源码:https://github.com/facebook/buck),通过baksmali反编译dex,也能得到相同的效果。(库地址:http://asm.ow2.org/)

全站即时通讯技术资料分类


[1] 网络编程基础资料:
TCP/IP详解 - 第11章·UDP:用户数据报协议
TCP/IP详解 - 第17章·TCP:传输控制协议
TCP/IP详解 - 第18章·TCP连接的建立与终止
TCP/IP详解 - 第21章·TCP的超时与重传
理论经典:TCP协议的3次握手与4次挥手过程详解
理论联系实际:Wireshark抓包分析TCP 3次握手、4次挥手过程
计算机网络通讯协议关系图(中文珍藏版)
NAT详解:基本原理、穿越技术(P2P打洞)、端口老化等
UDP中一个包的大小最大能多大?
Java新一代网络编程模型AIO原理及Linux系统AIO介绍
NIO框架入门(三):iOS与MINA2、Netty4的跨平台UDP双向通信实战
NIO框架入门(四):Android与MINA2、Netty4的跨平台UDP双向通信实战
>> 更多同类文章 ……

[2] 有关IM/推送的通信格式、协议的选择:
为什么QQ用的是UDP协议而不是TCP协议?
移动端即时通讯协议选择:UDP还是TCP?
如何选择即时通讯应用的数据传输格式
强列建议将Protobuf作为你的即时通讯应用数据传输格式
移动端IM开发需要面对的技术问题(含通信协议选择)
简述移动端IM开发的那些坑:架构设计、通信协议和客户端
理论联系实际:一套典型的IM通信协议设计详解
58到家实时消息系统的协议设计等技术实践分享
>> 更多同类文章 ……

[3] 有关IM/推送的心跳保活处理:
Android进程保活详解:一篇文章解决你的所有疑问
Android端消息推送总结:实现原理、心跳保活、遇到的问题等
为何基于TCP协议的移动端IM仍然需要心跳保活机制?
微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)
微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
移动端IM实践:实现Android版微信的智能心跳机制
移动端IM实践:WhatsApp、Line、微信的心跳策略分析
>> 更多同类文章 ……

[4] 有关WEB端即时通讯开发:
新手入门贴:史上最全Web端即时通讯技术原理详解
Web端即时通讯技术盘点:短轮询、Comet、Websocket、SSE
SSE技术详解:一种全新的HTML5服务器推送事件技术
Comet技术详解:基于HTTP长连接的Web端实时通信技术
WebSocket详解(一):初步认识WebSocket技术
socket.io实现消息推送的一点实践及思路
>> 更多同类文章 ……

[5] 有关IM架构设计:
浅谈IM系统的架构设计
简述移动端IM开发的那些坑:架构设计、通信协议和客户端
一套原创分布式即时通讯(IM)系统理论架构方案
从零到卓越:京东客服即时通讯系统的技术架构演进历程
蘑菇街即时通讯/IM服务器开发之架构选择
腾讯QQ1.4亿在线用户的技术挑战和架构演进之路PPT
微信技术总监谈架构:微信之道——大道至简(演讲全文)
如何解读《微信技术总监谈架构:微信之道——大道至简》
快速裂变:见证微信强大后台架构从0到1的演进历程(一)
17年的实践:腾讯海量产品的技术方法论
>> 更多同类文章 ……

[6] 有关IM安全的文章:
即时通讯安全篇(一):正确地理解和使用Android端加密算法
即时通讯安全篇(二):探讨组合加密算法在IM中的应用
即时通讯安全篇(三):常用加解密算法与通讯安全讲解
即时通讯安全篇(四):实例分析Android中密钥硬编码的风险
传输层安全协议SSL/TLS的Java平台实现简介和Demo演示
理论联系实际:一套典型的IM通信协议设计详解(含安全层设计)
微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解
来自阿里OpenIM:打造安全可靠即时通讯服务的技术实践分享
>> 更多同类文章 ……

[7] 有关实时音视频开发:
即时通讯音视频开发(一):视频编解码之理论概述
即时通讯音视频开发(二):视频编解码之数字视频介绍
即时通讯音视频开发(三):视频编解码之编码基础
即时通讯音视频开发(四):视频编解码之预测技术介绍
即时通讯音视频开发(五):认识主流视频编码技术H.264
即时通讯音视频开发(六):如何开始音频编解码技术的学习
即时通讯音视频开发(七):音频基础及编码原理入门
即时通讯音视频开发(八):常见的实时语音通讯编码标准
即时通讯音视频开发(九):实时语音通讯的回音及回音消除概述
即时通讯音视频开发(十):实时语音通讯的回音消除技术详解
即时通讯音视频开发(十一):实时语音通讯丢包补偿技术详解
即时通讯音视频开发(十二):多人实时音视频聊天架构探讨
即时通讯音视频开发(十三):实时视频编码H.264的特点与优势
即时通讯音视频开发(十四):实时音视频数据传输协议介绍
即时通讯音视频开发(十五):聊聊P2P与实时音视频的应用情况
即时通讯音视频开发(十六):移动端实时音视频开发的几个建议
即时通讯音视频开发(十七):视频编码H.264、V8的前世今生
简述开源实时音视频技术WebRTC的优缺点
良心分享:WebRTC 零基础开发者教程(中文)
>> 更多同类文章 ……

[8] IM开发综合文章:
移动端IM开发需要面对的技术问题
开发IM是自己设计协议用字节流好还是字符流好?
请问有人知道语音留言聊天的主流实现方式吗?
IM系统中如何保证消息的可靠投递(即QoS机制)
谈谈移动端 IM 开发中登录请求的优化
完全自已开发的IM该如何设计“失败重试”机制?
微信对网络影响的技术试验及分析(论文全文)
即时通讯系统的原理、技术和应用(技术论文)
开源IM工程“蘑菇街TeamTalk”的现状:一场有始无终的开源秀
>> 更多同类文章 ……

[9] 开源移动端IM技术框架资料:
开源移动端IM技术框架MobileIMSDK:快速入门
开源移动端IM技术框架MobileIMSDK:常见问题解答
开源移动端IM技术框架MobileIMSDK:压力测试报告
开源移动端IM技术框架MobileIMSDK:Android版Demo使用帮助
开源移动端IM技术框架MobileIMSDK:Java版Demo使用帮助
开源移动端IM技术框架MobileIMSDK:iOS版Demo使用帮助
开源移动端IM技术框架MobileIMSDK:Android客户端开发指南
开源移动端IM技术框架MobileIMSDK:Java客户端开发指南
开源移动端IM技术框架MobileIMSDK:iOS客户端开发指南
开源移动端IM技术框架MobileIMSDK:Server端开发指南
>> 更多同类文章 ……

[10] 有关推送技术的文章:
iOS的推送服务APNs详解:设计思路、技术原理及缺陷等
Android端消息推送总结:实现原理、心跳保活、遇到的问题等
扫盲贴:认识MQTT通信协议
一个基于MQTT通信协议的完整Android推送Demo
求教android消息推送:GCM、XMPP、MQTT三种方案的优劣
移动端实时消息推送技术浅析
扫盲贴:浅谈iOS和Android后台实时消息推送的原理和区别
绝对干货:基于Netty实现海量接入的推送服务技术要点
移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)
为何微信、QQ这样的IM工具不使用GCM服务推送消息?
>> 更多同类文章 ……

[11] 更多即时通讯技术好文分类:
http://www.52im.net/forum.php?mod=collection&op=all

附录:有关QQ、微信的文章汇总


[1] 有关QQ、微信的技术文章:
微信后台团队:微信后台异步消息队列的优化升级实践分享
微信团队原创分享:微信客户端SQLite数据库损坏修复实践
腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率
腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)
腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)
微信Mars:微信内部正在使用的网络层封装库,即将开源
如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源
开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]
微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解
微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)
微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)
Android版微信从300KB到30MB的技术演进(PPT讲稿) [附件下载]
微信团队原创分享:Android版微信从300KB到30MB的技术演进
微信技术总监谈架构:微信之道——大道至简(演讲全文)
微信技术总监谈架构:微信之道——大道至简(PPT讲稿) [附件下载]
如何解读《微信技术总监谈架构:微信之道——大道至简》
微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]
微信异步化改造实践:8亿月活、单机千万连接背后的后台解决方案
微信朋友圈海量技术之道PPT [附件下载]
微信对网络影响的技术试验及分析(论文全文)
一份微信后台技术架构的总结性笔记
架构之道:3个程序员成就微信朋友圈日均10亿发布量[有视频]
快速裂变:见证微信强大后台架构从0到1的演进历程(一)
快速裂变:见证微信强大后台架构从0到1的演进历程(二)
微信团队原创分享:Android内存泄漏监控和优化技巧总结
全面总结iOS版微信升级iOS9遇到的各种“坑”
微信团队原创资源混淆工具:让你的APK立减1M
微信团队原创Android资源混淆工具:AndResGuard [有源码]
Android版微信安装包“减肥”实战记录
iOS版微信安装包“减肥”实战记录
移动端IM实践:iOS版微信界面卡顿监测方案
微信“红包照片”背后的技术难题
移动端IM实践:iOS版微信小视频功能技术方案实录
移动端IM实践:Android版微信如何大幅提升交互性能(一)
移动端IM实践:Android版微信如何大幅提升交互性能(二)
移动端IM实践:实现Android版微信的智能心跳机制
移动端IM实践:WhatsApp、Line、微信的心跳策略分析
移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)
移动端IM实践:iOS版微信的多设备字体适配方案探讨
>> 更多同类文章 ……

[2] 有关QQ、微信的技术故事:
技术往事:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码
技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史
开发往事:深度讲述2010到2015,微信一路风雨的背后
开发往事:微信千年不变的那张闪屏图片的由来
开发往事:记录微信3.0版背后的故事(距微信1.0发布9个月时)
一个微信实习生自述:我眼中的微信开发团队
>> 更多同类文章 ……

即时通讯网 - 即时通讯开发者社区! 来源: - 即时通讯开发者社区!

上一篇:iOS版微信安装包“减肥”实战记录下一篇:微信团队原创资源混淆工具:让你的APK立减1M

本帖已收录至以下技术专辑

推荐方案
评论 3
文章前半部分写的还可以,大家思路无非也都是这样,后面有关so的优化啥的就有点不太靠谱了。
签名: 星期六,那又怎样,还是得上班
确认是微信团队写的吗?
写得真好
签名: 陈俊
打赏楼主 ×
使用微信打赏! 使用支付宝打赏!

返回顶部