Android APK瘦身

1,715 阅读7分钟

一、概述

为什么APK要瘦身。APK越大,在下载安装过程中,他们耗费的流量会越多,安装等待时间也会越长;对于产品本身,意味着下载转化率会越低(因为竞品中,用户有更多机会选择那个体验最好,功能最多,性能最好,包最小的),所以APK的瘦身优化也很重要,本篇博客将讲述APK瘦身的相关内容。

二、APK包分析

Android Studio工具栏里,打开build–>Analyze APK, 选择要分析的APK包,如下图:

  • lib文件夹:用于存放应用需要的库文件;
  • classes.dex文件:所有的Java代码最终都是转化成dex文件,运行在Android虚拟机上;
  • res文件夹:存放所有的资源文件;
  • resource.arsc文件:存放所欲资源文件的id映射;
  • META-INF文件夹:存放几个签名校验的相关文件,用于保证APK的完整性和安全性;
  • AndroidManifest.xml文件:Android应用的全局配置文件;
  • assets文件夹:用于保存需要保持原始文件的资源文件。

其中,在安装包中占比较大的包括:dex文件、res文件夹、assets文件夹、lib文件夹以及resource.arsc文件。所以,接下来的瘦身优化就是让这些文件变小,以此达到瘦身的目的。

三、瘦身方案

资源瘦身

对于绝大对数APP来说,只需要取一套设计图就足够了。鉴于现在分辨率的趋势,建议取720p的资源,放到xhdpi目录。

1.尽量只保存一份图片资源
2.使用 Drawable XMLColor.9 PNG 代替 PNG
  • 一些情况下,我们可以考虑使用 Drawable XML 来代替 PNG,如:渐变的背景图,用几行 XML 就可以描绘出来,何必使用几十到上百K的PNG 文件;
  • Color 代替 PNG,如:纯色的背景;
  • 从性能上看,比起使用图片资源需要先将其生成 Bitmap 再传到底层交由 GPU 渲染,用 Drawable XMLColor 则更加高效,它是直接将 Shape 信息传到底层由 GPU 进行渲染,CPU 和 内存的占用会更少;
  • .9 PNG 代替 PNG,场景很多,不举例了;
3.使用 JPG 代替 PNG

JPG 代替 PNG,由于 JPG 没有 Alpha 通道,所以文件更小,适用于不需要透明度的图片可以考虑。

4.谨慎使用 WebP 代替 PNG

由于 WebP 效果好,且相同效果下, WebP 文件比 PNG 文件要小得多 ,所以,网上很多人说使用 WebP 代替 PNG,对此,我保持异议。理由如下:

  • WebPAndroid 端,最低只支持 4.0 ,要兼容 4.0 以下的环境需要额外引入兼容库,反而增大安装包体积;
  • Android Studio 不支持预览 WebP 图片,引用 WebP 的布局文件也无法预览显示;
  • 解压了 BAT 们的应用,以及同类竞品,基本没有发现在资源文件中用 WebP 的;

官方介绍:https://developers.google.com/speed/webp/docs/precompiled

5.有损编码格式的音频文件代替无损格式的音频文件
  • 无损格式:WAV,PCM,ALS,ALAC,TAK,FLAC,APE,WavPack(WV)
  • 有损格式:MP3,AAC,WMA,Ogg Vorbis

实际开发中需要使用音频文件尽量采用 MP3、Ogg 这种有损格式,尽量不要用 WAV、PCM 这种无损音频。

6.移除无用的资源
android {
    buildTypes {
        release {
            shrinkResources true
        }
    }
}
7.清理无用资源

版本迭代过程中,不但有废弃代码冗余,肯定会有无用的图片存在。 在build.gradle 里面配置shrinkResources true,在打包的时候会自动清除掉无用的资源,但经过实验发现打出的包并不会,而是会把部分无用资源用更小的东西代替掉。

注意,这里的“无用”是指调用图片的所有父级函数最终是废弃代码,而shrinkResources true 只能去除没有任何父函数调用的情况。

这里使用 Android Studio 自带的工具来清理无用资源:

8.删除无用的语言资源

大部分应用其实并不需要支持几十种语言的国际化支持。还好强大的gradle支持语言的配置,比如国内应用只支持中文:

android {
    defaultConfig {
        resConfigs "zh"
    }
}
9.使用Tinypng有损压缩

Tinypng工具只支持上传PNG图片到官网上压缩,然后下载保存,在保持alpha通道的情况下对PNG的压缩可以达到1/3之内,而且用肉眼基本上分辨不出压缩的损失。 Tinypng的官方网站:http://tinypng.com/

10.缩小大图

如果经过上述步骤之后,你的工程里面还有一些大图,考虑是否有必要维持这样的大尺寸,是否能适当的缩小。

事实上,由于设计师出图的原因,我们拿到的很多图片完全可以适当的缩小而对视觉影响是极小的。

11.覆盖第三库里的大图

有些第三库里引用了一些大图但是实际上并不会被我们用到,就可以考虑用1x1的透明图片覆盖。

你可能会有点不舒服,因为你的drawable下竟然包含了一些莫名其妙的名称的1x1图片

12.精简SO
  • 删除armable-v7包下的so
    • 基本上armable的so也是兼容armable-v7的,armable-v7a的库会对图形渲染方面有很大的改进,如果没有这方面的要求,可以精简。
    • 这里不排除有极少数设备会Crash,可能和不同的so有一定的关系,请大家务必测试周全后再发布。
  • 删除x86包下的so
    • x86包下的so在x86型号的手机是需要的,如果产品没用这方面的要求也可以精简。 建议实际工作的配置是只保留armable、armable-x86下的so文件,算是一个折中的方案。

在模块的build.gradledefaultConfig下加入以下ndk配置:

ndk {
    moduleName "myNativeLib"
    ldLibs "log", "z", "m"
    abiFilters "armeabi", "x86", "armeabi-v7a", "x86_64", "arm64-v8a"
}
  • moduleName是随便写的,与将来在Java类中使用System.loadLobrary(“本地库名称”);以及生成的.so文件名称对应;
  • ldLibs是要用到的jni库,一般由google提供,比如上边引入的log库可以让我们在C代码中使用LogCat日志;
  • abiFilters指的是我们要生成哪些平台的so文件,这里生成arm平台和x86平台。
13.使用微信资源压缩打包工具

微信资源压缩打包工具通过短资源名称,采用7zipAPP进行极致压缩实现减小APP的目标,效果非常的好,强烈推荐。

建议开启7zip,注意白名单的配置,否则会导致有些资源找不到,官方已经发布AndResGuardgradle中了,非常方便:

会生成一个andresguard/resguard的Task,自动读取release签名进行重新混淆打包。

14.矢量图

矢量图是由点与线组成,和位图不一样,它再放大也能保持清晰度,而且使用矢量图比位图设计方案能节约30~40%的空间,现在谷歌一直在强调扁平化方式,矢量图可很好的契合该设计理念。

  • 优势

    • (1)占用存储空间小
    • (2) 无极拉伸不会出现锯齿,可以照顾不同尺寸的机型
    • (3)Android Studio自带很多资源,减小UI工作量
  • 劣势

    • (1) 只支持5.0及以上系统
    • (2) 与位图相比多了一层计算,需消耗更多性能
    • (3) 不支持.9图
    • (4)不适合表现真实照片和复杂图形,一般使用在简单的icon和动画上
15.使用shape背景

特别是在扁平化盛行的当下,很多纯色的渐变的圆角的图片都可以用shape实现,代码灵活可控,省去了大量的背景图片。

参考

你必须要懂的APK瘦身知识