您的位置:首页 > 其它

APK 瘦身之路

2017-10-10 13:59 429 查看

APK 瘦身之路

先说一下我对 apk 瘦身的看法,对开发流程有哪些实际的意义:

减少了 apk size,这是最明显的体验。

减少了资源和代码文件之后,我们开发的时候,debug能更快一点(debug 一般不开启混淆,会把全部资源和代码,进行build)

通过分析 apk,可以评估一些规范,例如 png 文件处理规范,评价第三方库和so的价值,更重要的是我们能够更好的清楚,我们写代码的时候的一些规范,例如是否需要创建新的 class,怎么处理废弃的 class,怎么处理废弃的资源。

这里先说下 apk 瘦身的思路,首先通过apk analyse 工具(例如AS 自带的分析工具),分析出 apk 的文件占比大小,然后根据统计结果,制定瘦身方案。

apk analyse

Android Studio Apk Analyzer

这里首先使用了AS 自带的分析工具,对线上的 apk 进行分析(酷狗8.6.8,繁星3.1.5),分析结果如下:

酷狗



繁星



上面看到的只是总体情况,下面我们进入文件占比最大的几块,进行分析,这里分析的是线上包,由于开启了资源混淆,所以这里看到的文件名都是混淆之后的。

首先这几张700Kb的大图就应该处理掉~~



APk 瘦身

代码混淆和压缩资源(ProGuard 和 ShrinkResources)

这里两个做法是 android 官方提供的做法,可以达到以下效果:

ProGuard 会检测和移除封装应用中未使用的类、字段、方法和属性,包括自带代码库中的未使用项(这使其成为以变通方式解决 64k 引用限制的有用工具)。ProGuard 还可优化字节码,移除未使用的代码指令,以及用短名称混淆其余的类、字段和方法。

代码压缩器移除所有未使用的代码后,资源压缩器便可确定应用仍然使用的资源。这在您添加包含资源的代码库时体现得尤为明显——您必须移除未使用的内容库代码,使内容库资源变为未引用资源,才能通过资源压缩器将它们移除。

所以通过代码混淆和资源压缩,可以在打包的时候避免引入无用的代码(类,方法,字段)和资源(不包含string,color等)。

更好的混淆方案

这里的话,采用的是 微信团队的混淆方案。AndResGuard,这里的话,我这边正在尝试,因为涉及到多渠道打包的问题,我这边利用下班时间正在做尝试,根据微信的开发者的说明,之前这个混淆方案大约帮助微信减少了1MB的大小(运来大小35MB的样子)

图片压缩

这里采用的压缩方案是 pngquant(gui)+tinypng 下面是压缩处理的结果(包含了 appt 打包前后的对比):

参数apk size(压缩前/压缩后)资源文件大小(压缩前/压缩后)压缩比例(资源)
酷狗34.8MB/34.6MB10.3MB/10MB/
繁星31.4MB/29.2MB11.6MB/9.4MB18.96%
tip:

使用 pngquant 压缩图片,如果图片是 jpg 格式,会被自动转为 png 格式。

考虑过用其它压缩工具,体验的感觉是千篇一律,而 pngquan 支持最全面。

最终的一些结果:

需要商议指定图片文件的准入规范,因为在压缩过程发现,繁星项目有三张接近800kb的jpg文件,这些肯定是需要压缩的。

和设计部门确认图片规范,例如需要删除 ps 处理之后的图片元数据信息,需要指定位深度,背景图的处理



图片适配的问题

drawable 文件夹的适配问题

我们都知道,android 系统会根据屏幕密度对我们的 drawable 图片进行适配,例如



这里为什么要考虑这个问题,因为你在 src 或者 background 里面使用一个图片,这里是不会自动进行 resize的,只会根据scaletype 和View大小(宽和高)对你的图片大小(分辨率)进行适配。

下面是做的一个实验,放置同一张分辨率和大小在不同的 drawable (hdpi,xhdpi,xxhdpi,xxxhdpi,nodpi)文件夹下,然后将五张图片设置为 相同大小ImageView 的src 属性,最后计算 ImageView BitmapDrawable 的大小,关键代码和drawable 文件夹情况如下:



BitmapDrawable b1 = (BitmapDrawable) imgv1.getDrawable();
tv1.setText("bitmap 大小:"+b1.getBitmap().getRowBytes());


然后得出的结果如下:



注意这里适配drawable 是根据屏幕密度,而不是屏幕分辨率,例如 nexus 5X 的屏幕密度是 420 dpi,会被当作是

这里发现的一个小问题是,在不同 SourceSet 下放置了同名的文件,是被当作同一文件的(资源id是一样的),但是ide 不会提示同名冲突的问题。

所以这里针对图片资源给出以下策略

1. 尽可能的压缩图片,制定图片资源入代码库的规范(我所在的团队使用tinypng 的 as 插件进行压缩,或者把压缩工作交付给设计师)

2. 尽量少用图片做背景,即便要用也可以考虑局部用图片

3. 尽量保持适配最常见的分辨率

Dex 方法数详解

由于单个 Dex 限制了代码引用的代用总数不能高于 65536,随着业务膨胀,方法数自然会爆炸,所以需要拆分多个 dex。

根本原因

dex 方法数目受限的根本原因在于 Dex 的文件格式,由于字节码在调用方法时,必须显示寻址方法在 dex 存储的索引,即meth@BBBB[2]。BBBB 的含义是每个四位,四个 B 就是十六位,所以最多支持 2^16 个方法。

那么这些的方法都包含了那些方法?

自己编写的 java 文件中的代码

Android 框架方法

引用的第三方库的方法

ART 虚拟机

在 5.0 以后(API 21) 以后,android 系统会在 apk 安装时候,扫描 dex 文件,将多个 dex 文件预编译成一个 .oat 文件,方便 android 系统使用。但是在 5.0 以前的系统中,为了支持多个 dex,编译器做了很多决策去决定哪些 class 文件是包含在主 dex 中。所以这种情况下,build 的速度会比单个 dex 要慢上很多,开发模式下,你可以通过配置多个 product flavor 避免 multi dex,来提高开发速度。

如何避免

减少依赖文件

通过 proguard 移除无用的代码

总的来说,dex 爆炸不会对启动速度有太大的负担,主要是从 apk 大小考虑的话,可以避免无谓增加方法数的做法。

参考文档:

关于 shrink https://developer.android.com/studio/build/shrink-code.html

android适配 drawable的方式https://android-developers.googleblog.com/2014/10/getting-your-apps-ready-for-nexus-6-and.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息