Android apk包体优化

1.概述

在 2018 年的 Google I/O,Google 透露Google Play 上安装包体积与下载转化率的关系如下图:
gp转化率.png

从图中我们可以看出来随着apk的体积增大,转化率逐渐下降。而包体对应用的影响主要有以下几点:

  • 下载转化率:一个近100M的应用用户在点击下载之后,因为网速过慢,用户会在犹豫的过程中取消下载,而一个10M的应用在用户犹豫的过程中却已经下完了。
  • 推广成本:
    1. 应用的预装对单个apk的体积有限制,apk的体积会影响到应用的单价。
    2. 一些移动开发者会把apk置于官网下载,体积过大不仅使得用户浪费流量,也使得开发者服务器流量浪费。
  • 应用市场:
    苹果已经限制当应用体积大于150M的时候只能WIFI下载,而谷歌市场要求当应用apk大于100M的时候使用 apk扩展文件上传(可参照之前的文章了解),此也为应用商店对带宽压力的一方面考虑。

在现如今众多的超级app随着业务的不但增加,需求的不但演进apk体积在不断增加,apk体积优化闲得尤为重要。google play上有一款应用via浏览器,因为其应用体积小,功能相对齐全。优势明显比其他同类品牌的产品强出不是零星半点。

2. apk打包流程

既然是优化apk体积,追本溯源,当然是从apk产生的过程来分析,在网上我们可以查到apk的组成主要由资源,代码和第三方库,如 so 库等部分组成。开发过中主要是通过ant、gradle等方式编译生成安装包,具体流程如下:
apk打包流程.png

有此图我们大致可以看出apk体积的优化我们可以从resources,dex和其他资源库三个方向去优化。将apk解压或者通过Android Studio等工具来解压,主要关注以下几个方面:

  1. dex个数和每个dex方法数的情况
  2. 没有alpha通道的png图,可压缩成jpg减少体积;
  3. 超过一定数值的大文件,特别是图片资源可采用有损压缩;
  4. 新增文件、减少文件,文件大小发生变化的情况;
    下面我们从上述流程中提到的几个方面去分析apk瘦身的方法。

3. Resources优化

Android资源管理框架实际是由AssetManager和Resources两个类来实现的。其中,Resources类可以根据ID来查找资源,而AssetManager类根据文件名来查找资源。事实上,如果一个资源ID对应的是一个文件,那么Resources类是先根据ID来找到资源文件名称,然后再将该文件名称交给AssetManager类来打开对应的文件的。而Resources是通过resources.arsc把Resource的ID转化成资源文件的名称,然后交由AssetManager来加载的。关于resources.arsc的格式可以在Android源码“/frameworks/base/include/androidfw/ResourceType.h”下查看。

  1. 删除无用资源:
    在不停的迭代中,或多或少会出现无用的资源,包括但不限于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'
        }
    }
}
  1. 图片处理
  • 对于体积特别大(超过50k)的图片资源可以考虑有损压缩,jpg采用优图压缩,png尝试采用pngquant压缩,输出视觉判断是否可行;
  • 对assets中的图片资源也使用aapt的crunch做图片预处理;
  • crunch有可能会使图片变大,在这种情况,我们可以替换成原图。需要注意的是对于.9.png,由于crunch过程中去除了黑边,所以不能替换;
  • 对于没有透明区域的png图片,可以转成jpg格式。
  • 采用如webp,svg等格式文件。
    关于图片压缩可以采用一些第三方的网站压缩如熊猫推荐一个自己写的脚本ImageProcess通过该网站批量压缩图片。
  1. 字符编码
    resources.arsc中的会有一个去重过的字符串资源池(相同的两个字符串其实用的是同一份),每个String使用偏移值来获取资源池中的数值。ResourceTable的编码对于resources.arsc的体积有很大影响。这样的好处就是处理纯英文等直接通过ascii存储语言的国家资源文件将会更小,而对于中文、日文这些国家的资源文件有可能会变大。
  2. 指定文件的压缩方式与7zip压缩
    安装包是一个压缩文件,我们可以指定里面的文件采用哪种压缩方式,比如一些文件我们可以采用一些极致压缩到最小,然后安装成功后再解压,或者安装完成后从服务器下载再解压,但此举会对启动速度有一定的影响。
  3. 语言包动态加载
  4. 资源混淆,我们常常用proguard来混淆代码,同样资源也是可以混淆的,会生成a,b,c命名的png 和xml,让反编译更加难受,不过这其中需要注意资源映射问题。
  5. 产品做减法。

4. Dex 优化

对于大部分应用来说Dex的个数和Dex的体积是整个应用的大部头,因此Dex的优化在对包体优化起到了关键作用,主要有以下几个部分:

  1. ProGuard 混淆
    你可以通过下面的方法输出 ProGuard 的最终配置,需要注意各种的 keep *,很多情况下我们只需要 keep某个包名,方法名,类名即可。
-printconfiguration  configuration.txt

但我们可以加大力度混淆,比如对非export的四大组件和View进行混淆,但我们要注意以下两个方面的问题

xml

清单文件中的xml需要同步修改

代码替换

代码中不可出现运算拼接出来的类名

// 情况一:变量
public String activityName = "com.sample.TestActivity";
// 情况二:方法体
startActivity(new Intent(this, "com.sample.TestActivity"));
// 情况三:通过运算得到,不支持
startActivity(new Intent(this, "com.sample" + ".TestActivity"));

饿了么曾经实现过一款混淆四大组件的库Mess,具备一定的参考价值。
Android Studio 3.0推出了Android新Dex编译器D8与新混淆工具R8可以在编译过程中生成的dex大概减少3%,但此功能还在测试阶段。

  1. Dex 分包
    正如我们所知同一个应用可能会存在多个Dex包,每个Dex 包的也会存在相互之间的引用,因此在Dex的分包规则上我们同样具备优化的方法,比如避免Dex包之间的冗余和Dex包生成的算法优化。具体的我们需要先了解Dex文件的格式和生成规则,其中主要是优化Dex的格式中debugItems模块。

5. 其他资源优化

一个应用除了Java代码,resource等资源之外,还存在一个Native library等相关资源。这块主要是针对一些Native 资源进行优化。

  1. 减少冗余
    例如一些so库中C++运行库大多使用静态编译方式,使用stlport_shared方式可减小APK包大小,相当于把大家公有的代码提取出来放一份,减少冗余。同时也会节省一点内存,加载so的时候动态库只会加载一次,静态库则随着so的加载被加载多份内存映像。主要为了减少冗余模块。大家都用到的一些基础功能,应该抽成基础模块。
  2. so库压缩
    我们可以针对一些so库进行特殊压缩,需要时解压,甚至可以从网络获取到本地进行加载。

以上为对apk体积优化的一些总结,当然会还有一些其他的可以优化的点,欢迎大家补充。
针对资源压缩主要是目前浏览器引用微信的AndResGuard有着明显的效果。

参考
极客时间Android开发高手课
Dex文件格式详解
美团Android App包瘦身优化实践
支付宝Android 包大小极致压缩
微信Android安装包相关知识汇总
FaceBook Redex

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容

  • 本文来自尚妆Android团队青峰发表于尚妆博客 APK瘦身探索 最近几周一直在研究如何为APK瘦身,折腾了很久,...
    尚妆产品技术刊读阅读 1,787评论 1 23
  • 最近一直在研究关于apk瘦身方面的知识,看了很多文章受益匪浅。原文地址 http://tech.meituan.c...
    王元_Trump阅读 3,748评论 1 30
  • 最近几周一直在研究如何为APK瘦身,折腾了很久,是时候写篇博客总结一下了,虽然已经准备了下周一要在客户端周会分享用...
    风清袖一阅读 1,058评论 1 10
  • 1、 前言 如果你对App优化比较敏感,那么Apk安装包的大小就一定不会忽视。关于瘦身的原因,大概有以下几个方面:...
    未来的理想阅读 11,174评论 4 39
  • 俗话说三天打鱼,两天晒网,说的就是我这种人吧,从第三天直接记到第六天了。哈哈,先来回忆下前两天做了什么。 第四天是...
    叶美珍阅读 246评论 0 2