十分钟把Apk 极限压缩,从贾玲瘦成林志玲!

152 阅读6分钟
原文链接: www.jianshu.com

1.引言

关于 Apk的压缩与优化,这是一个老生常谈的话题了。大家耳熟能详的方法就有很多,比如开启混淆,压缩图片,使用 SVG,去除无用库,使用 AndResGuard 之类的。这些网上已经有太多教程了,我就不再赘述了。今天这篇文章,是想和大家分享下不那么耳熟能详的思路。

2. 思路

去年我也写过一篇关于 Apk压缩的文章,当时老板说要推广应用,为了方便用户下载,叫我把 Apk 弄小点。最开始经过上面提到的那些操作后,安装包减少了《Android性能调优;如何让你的APK瘦身88%》感兴趣的可以去看下。当然,这种做法现在已经很普遍了。

3. 分析

我觉得 Apk 优化,在代码本身已经写的比较规范的情况下,常规的压缩操作带来的效果是非常有限的。如果想要做到极限压缩,那就一定要用一些"非常手段",这不仅要从技术层面考虑,还要结合产品自身的特点。比如产品针对的用户群体,产品面向的市场范围等。

拿最近发布的 Readhub+ App来说:

  • v1.0.0 版本,Apk 大小 1.14M
  • v1.2.0 版本,Apk 大小 1.13M
  • v1.5.0 版本,Apk 大小 861K
  • v1.8.0 版本,Apk 大小 858.25K

功能虽然在一直增加,但安装包却在一直在减小。而且如果要较真的话,这仍然称不上是极限状态,因为项目中还是用到了很多三方库,如果把这些库都去掉的话,可能最终只有不到 500K 的样子。不过 800K 相较于现在动不动就好几十兆的 App 来说,简直已经是可以忽略的大小了,所以也就不打算继续在这上面耗时间了。

4.拷贝


再说回到 Readhub+ Apk 的优化上,其实说实话,我觉得也没什么太有技术含量的操作,可能只不过是你压根没往那个方面想而已。而且这个也要结合项目自身的特点,所以这篇文章更多的是希望提供一个思路而已。

为了在 v1.2.0 的基础上,继续减小 Apk 的体积,我用 Android Studio 自带的工具分析了 Apk 文件的组成。如下图所示,其中 support 包就占了很大的体积,但是包中大部分的组件我都没有用到,虽然已经开启了混淆,但是再怎么混淆,也只是减小了文件的大小,并没有完全去除文件。


于是我就想着能不能把 support 包中无用的文件去掉。开始想通过编译的手段实现,在网上搜了一圈后,发现 gradle 目前好像不具备排除 jar 包中指定类的能力,而且即便有,那也是一个巨大的工程了。所以只能通过笨办法了,拷贝 support 包中的源码。在之前的项目中,已经默认习惯了引入 v4 包和 v7 包,所以开始优化 Apk 的时候也压根没有朝这个方面想。

正如我刚开始所说,思路还是很简单的。但比较奇怪的是,当我搜索网上关于 Apk 优化的文章时,几乎没有哪篇提到这种做法的,也不知道是不是因为这种做法太 low 了,简直让很多人难以启齿?还是这压根都不能算个方法?

但尽管拷贝听起来很“无脑”,可我觉得对于没有这样做过的人来说,还是很容易走一些弯路的。因为我在拷贝的过程中,就遇到了一些问题。(肯定有人心想,连代码拷贝都能出问题?真“辣鸡”,哭笑不得.jpg)。因为 support 包中代码非常多,所以拷贝哪个版本,拷贝哪些文件,怎么拷贝都算是问题。

4.1 拷贝哪个版本

Readhub+ 拷贝的是 androidx 中的代码,因为相较于 27.0.0 和 28.0.0,甚至更早版本的 support 包来说,谷歌对 androidx 的包结构做了更加细化的区分,而且将很多 Material Design View 类组件都拆分到了一个单独的 material-components 开源仓库中,这样拷贝起来也就更加方便了。

4.2 怎么拷贝

在操作过程中,我发现拷代码其实是比较简单的,比较麻烦的是拷贝 support 包中各种 res 资源,不过这里有两种做法可以减少一些工作量。第一种是通过在 gradle 设置 sourceSets 属性,将不同包中的 res 资源区分开。第二种就是新建一个Android Module 专门用来放 support 包中的各种 res 文件。这样就不会和自己项目中的资源混起来了,后期管理和维护起来也比较方便,Readhub+ 就是用的这种方式。

4.3 拷贝哪些文件

这个就有点因人而异了,应该说是因项目而已了,如果你追求极致的小,那么尽量不要拷贝 View 类的组件了,想要什么效果可以自己手写一个。因为 support 包的 View 组件,很多都考虑了兼容问题,所以有很多代码都是为了提高对低版本的兼容性而写的。这可能对于你们的项目来说是完全多余的。

可能有些人会有疑问,这么直接拷贝代码,不利于后期的升级维护啊。这个我觉得大可放心,首先 support 包的升级频率是非常低的,加上我们拷贝的是稳定版中的代码,除非出现了致命性的 bug,不然就算不升级一般也不会有什么问题。

通过一通拷贝之后,Readhub+ 中 support 代码占用的体积减少了 46.7%,一下就减少了好几百K,这对于一个本身只有 1.2M 的应用来说,已经是相当大的瘦身了,简直就是从贾玲瘦成了林志玲!

5.还没结束


通过拷贝 support 包的代码,已经让 Apk 的体积小了不少,但还是有继续优化的空间的。这就又要提到文章开头说的,需要我们要结合产品自身的特点,进行一些定向的优化了。

比如产品的定位,投放的市场,针对的用户等。如果产品只投放到国内市场,那么我们可以在 gradle 中配置只保留 zh 这部分语言资源,这也可以减小十几 K的大小;还有,如果我们针对的是比较年轻的用户,那么在适配分辨率的时候,可以只考虑 xxhdpi 以上的设备,甚至连 logo 也可以只保留一套,在 Readhub+ 中就是这样做的。

splits {
    density {
        enable true
        exclude "mdpi", "ldpi", "hdpi", "xhdpi", "xxxhdpi"
        compatibleScreens 'small', 'normal', 'large', 'xlarge'
    }
}

当然,还有一些其他方式,这个就和项目本身有很大的关联了,所以这里也只能提供一个思路而已。还是文章开头那句话,如果你真的想让你的 Apk 变得非常小,那就一定要结合项目自身的特点去分析,看哪里还能减小体积的。

推荐阅读:

《上海大厂Android面试经历;华为+小米+映客+抖音》
《别人花了几万元学的Android高级技术,我帮你们免费弄来了!》