Apk 极限压缩(说点不同的)

1.引言


Readhub+ 发布后,后台有人留言要源码的,还有人问 Apk 怎么压缩的。可是目前还不打算开源,因此没有源码。不过却是能够分享一下我在压缩 Readhub+ Apk 的一点小小的心得。android

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

2. 思路


几年前,我也写过一篇关于 Apk压缩的文章,当时老板说要推广应用,为了方便用户下载,叫我把 Apk 弄小点,毕竟当时流量费仍是挺贵的。最开始通过上面提到的那些操做后,安装包只减小了 1M 左右,优化效果并不明显,由于写代码的时候已经比较注意规范了,因此常规的优化操做效果有限。github

后来,通过仔细分析了 Apk 的组成后,我发现有一个层级比较深的页面用到了地图,由于地图会引入 so 文件,就会致使 Apk 体积增长不少。因此我很机(ji)智(zei)的用 js 地图代替了原生地图,一会儿 Apk 就只剩下 3M多了,这是当时那篇文章,《Android快速实现地图功能(不只快!并且小!)》,感兴趣的能够去看下。固然,这种作法如今已经很广泛了。bash

3. 分析


我以为 Apk 优化,在代码自己已经写的比较规范的状况下,常规的压缩操做带来的效果是很是有限的。若是想要作到极限压缩,那就必定要用一些"很是手段",这不只要从技术层面考虑,还要结合产品自身的特色。好比产品针对的用户群体,产品面向的市场范围等。工具

拿我最近发布的 Readhub+ App来讲:gradle

  • 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 来讲,简直已是能够忽略的大小了,因此也就不打算继续在这上面耗时间了。优化

既然提到了,就顺便说一下吧,Readhub+ 的 v1.8.0 版本也发布了,加入了不少设置功能,因为这个不是本文主要内容,就不具体说了,我把更新日志单独写到了一篇文章里,须要的朋友能够到公众号看《 Readhub+ 更新日志》。网站

4.拷贝


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

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

因而我就想着能不能把 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 变得很是小,那就必定要结合项目自身的特色去分析,看哪里还能减少体积的。

虽而后面这些操做减小的体积并很少,只有几十 K 的样子,但这是在Readhub+ 仅有 800 多 K 的基础上减少了这么多。在这个体积下,哪怕每减少 1K也都是挺不容易的了。

最后,文章看完了,可能有些人比较懵逼,我在文中反复提到的 Readhub+ App是个什么应用?这是我最近发布到酷安市场的一款三方Readhub 客户端,至于 Readhub 又是干吗的?简单点说就是个高效获取新闻的网站,感兴趣的能够本身百度下。至于应用下载,能够在我公众号对话窗口回复:Readhub 获取。


相关资源:

推荐阅读: