随着APK功能越来越多、越来越复杂,APK的体积也变得越来越大。当用户去看APK描述时,惊叹:哇!这么多功能,赶紧下载来玩一下。但用户真正点击下载后,发现APK体积这么大,擦!如果没WIFI,下载又耗流量,安装又占内存。经过衡量后,用户可能选择终止下载,这样一来很容易造成用户流失。为了更好用户体验,我们得保证功能多样化的同时,APK体积又足够小。那么,让我们共同探讨下如何对APK进行全面瘦身。
理解APK结构
APK文件由ZIP文档组成,包含你应用程序的所有文件。这些文件包括:java类文件、资源文件和编译资源。
APK包含以下目录:
META-INF/:包含CERT.SF和CERT.RSA签名文件,也包含MANIFEST.MF文件;
assets/:包含app的assets,可以通过AssetManager对象来检索;
res/:包含没有编译进resource.arsc文件的资源;
lib/:包含编译代码,各种平台架构:armeabi,armeabi-v7a,armeabi-v8a,x86,x86_64,mips;
resource.arsc:包含编译资源,打包工具抽取XML内容,编译成二进制格式,并且保存起来;
class.dex:编译成DEX格式文件,让ART/Dalvik虚拟机能够识别;
AndroidManifest.xml:包含Android核心的manifest文件,四大组件、包名、版本号、版本名称、权限等等;
移除无用资源代码
Android Studio自带的lint工具,用于静态代码分析,检查你/res目录下的没有引用的文件。当lint工具在你的工程发现潜在的无用代码时,会打印如下信息:
res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
to be unused [UnusedResources]
另外,在gradle.build配置文件添加代码混淆:
android {
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
只需支持特定像素密度
Android支持各种型号设备,每种型号的屏幕密度不同。在Android4.4及以上,支持分辨率包括:ldpi、mdpi、hdpi、xhdpi、xxhdpi和xxxhdpi。我们没必要适配所有设备,只需要选择特定分辨率进行适配,这样可以减少图片资源的引入。
减少动画帧数
帧动画对APK体积影响很大。例如,原来引入30帧动画,可以在不影响动画效果前提下,适当减少帧数。
使用Drawable对象
一些图片并不需要静态图片资源,这种情况下,我们可以使用Drawable代替静态图片。这样可以减少图片资源。
复用资源
可以为图像的变化添加单独资源,比如:浅色、形状、旋转等。但是,推荐复用相同资源,在运行时再自定义改变。Android提供几种方式来改变颜色,Android5.0以上,可以使用android:tint和android:tintMode。如果是Android5.0以下,可以采用ColorFilter类进行设置。你也可以删除原有旋转效果资源,使用相同效果更加简单方式实现。以下代码用于实现箭头的展开与收起,通过把原图旋转180°:
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:drawable="@drawable/ic_arrow_expand"
android:fromDegrees="180"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="180" />
优化PNG文件
aapt工具可以在编译过程使用无损压缩方式,优化res/drawable目录的图片资源。比如,aapt工具可以使用颜色调色板,不需要256种color情况下,把true-color的PNG图片转成8位。这样图片质量不变,但是所占内存更小。你需要在gradle进行如下配置:
aaptOptions {
cruncherEnabled = false
}
压缩PNG和JPEG文件
你可以使用有损压缩工具:pngcrush、pngquant或者zopflipng,对PNG文件进行压缩。可以使用packJPG工具对JPEG文件进行压缩。
webP格式用起来
在你的图片中,你可以使用webP格式代替PNG或者JPEG。webP提供有损压缩(像JPEG一样),也提供透明度处理(像PNG一样)。但是,可以压缩效果比PNG和JPEG好。你可以在android Studio里把PNG或者JPEG格式图片转换成webP格式,选中图片右击,最后一栏:
看下webP与jpg对比,图片质量相同,但webP格式所占内存要小一点:
使用矢量图
你可以使用矢量图创建独立分辨率的图标,使用这些图片可以显著减少你APK体积。在Android中,矢量图是以VectorDrawable对象来表示。使用矢量图,100个字节的文件可以生成屏幕大小的清晰图像。具体用法如下:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="64dp"
android:width="64dp"
android:viewportHeight="600"
android:viewportWidth="600" >
<group
android:name="rotationGroup"
android:pivotX="300.0"
android:pivotY="300.0"
android:rotation="45.0" >
<path
android:name="v"
android:fillColor="#000000"
android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
</group>
</vector>
但是,矢量图需要很长时间来渲染。这算是以时间换空间的代价。考虑到这点,只在图片比较小的情况下,才采用矢量图。
移除枚举
一个枚举变量可以在class.dex文件里增加1.0到1.4KB。这些额外体积会迅速增加系统和共享库的复杂性。可以的话,使用@IntDef和ProGuard把枚举变量移除掉,并且把他们转换成整型。
大半夜写博客的好处是安静,虽然有点困。希望这篇文章可以帮助大家成功实现APK瘦身,如果有好的建议大家也可以分享下。程序员的最终目标:让代码变得更加简洁,让用户体验变得更好!