目录
1.App为何臃肿?
Android出现的最初几年里很少有几十兆的APP,但是现在我们却发现几十兆的应用比比皆是,出现这种情况的原因主要有以下三种:
Android碎片化的发展使得dpi的分类越来越多,从最初的ldpi、mdpi、hdpi到后来的xhdpi、xxhdpi、xxxhdpi、tvdpi等。
过多的引入第三方的函数库和SDK,不可避免的多了一些重复的代码及资源文件。
用户对APP视觉要求的不断提高,APP提供的资源细节越来越丰富,占用的体积不断上升。
2.APP的体积优化
根据APP臃肿的原因我们对APP的体积优化也主要是围绕以上三个方面来进行的。
2.1图片资源的优化
2.11 Android中使用的图片格式
在介绍优化图片资源之前我们先来了解下Android中的图片格式。
/** * Specifies the known formats a bitmap can be compressed into */ public enum CompressFormat { JPEG (0), PNG (1), WEBP (2); CompressFormat(int nativeInt) { this.nativeInt = nativeInt; } final int nativeInt; }
通过查看Bitmap的源码,我们可以发现Android中支持的编码格式有JPEG、PNG、WEBP三种。另外我们还可以通过引入第三方函数库实现对GIF的支持,接下来分别介绍一下这四种格式的特性。
JPEG:是一种广泛使用的有损压缩图像的标准格式,它不支持透明和多帧动画,一般影视类作品最终都是以JPEG格式展示。通过控制压缩比,可以调整图片大小。
PNG:PNG是一种无损压缩格式,它支持完整的透明通道,从图像处理领域讲,JPEG只有RGB三个通道,而PNG有ARGB四个通道。由于是无损压缩因此PNG图片一般占用空间比较大,会无形中增加APP大小,所以我们在为APP瘦身时一般都要对PNG图片进行处理以降低其大小。
GIF:诞生于1987年,特点是支持多帧动画,社交平台上的各种动态表情大部分是基于GIF来实现的。
WebP:由Google在2010年发布的,它支持有损无损压缩、支持完整的透明通道、也支持多针动画,是一种比较理想的图片格式。目前国内像微信淘宝等都已经应用了WebP,所以在既保证图片质量又限制图片大小的情况下WebP应该是首选。
2.12 优化图片资源
现如今我们在搭建APP界面的时候几乎都是使用PNG格式的图片,所以接下来会介绍几个对PNG进行压缩或修改的工具。
无损压缩:ImageOptim
ImageOptim是一个无损的压缩工具,它通过优化PNG的压缩参数,移除冗余元数据以及非必须的颜色配置文件等方式,在不牺牲图片质量的前提下,既减少了PNG图片占用的空间,又提高了加载速度。有损压缩:ImageAlpha
ImageAlpha是ImageOptim作者的一个有损的PNG压缩工具,相比较而言,图片的大小得到极大的减低,当然同时图片的质量也会受到一定程度的影响,经过该工具压缩的图片,需要经过设计师的检验才能最终上线,否则可能会影响到整个APP的视觉效果。有损压缩:TinyPNG
TinyPNG也是比较知名的有损PNG压缩工具,它以Web站点的形式提供,同所有的有损压缩工具一样经过压缩后的图片需要经过设计师的检验才能上线。PNG/JPEG转换为WebP
经过Google的测试无损压缩呢后的WebP比PNG文件少了45%的文件大小,即使这些PNG文件经过其他无损压缩工具的压缩后,WebP依然可以减少约28%的文件大小。不过需要注意的是在Android4.0之上如果想要支持WebP需要集成第三方函数库如:webp-android-backport来实现对WebP的支持。另外对于具有Alpha通道的PNG图片来说,如果需要在Android4.2.1之前的系统上运行,那么不能转换成WebP格式因为只有在Android 4.2.1以上的系统中,才能解析具有Aplha通道的WebP图片。WebP转换工具可以选择智图和iSparta等。尽量使用NinePath格式格式的PNG图片
.9.png图片格式简称NinePath图,它是针对Android平台的一种特殊格式的PNG图片格式,可以在图片指定的位置拉伸或者填充内容。NinePath的优点是体积小、拉伸不变形、能够很好的适配Android机型。Android Studio中自带了NinePath图的编辑工具,右键图片选择Create 9-Patch file即可创建.9.png图片。
2.2 使用Android Lint删除无用资源
Proguard只会对Java代码起作用,对于res/drawable/* 目录中的图片如果没有使用到,Proguard只会移除该图片在R文件中的引用,不会删除该图片。这时就需要用到Android Lint。Android Lint集成在Android Studio中,它会分析res目录下的资源文件,但不会分析assets目录下的资源文件。
当然我们不能过度依赖工具还要人工确认是否真的多余,例如某些资源是通过Java反射机制来使用的,这时Android Lint还是会检测出资源没有使用到。
2.3 利用Android Gradle配置
在Android Studio中我们可以通过配置app/build.gradle来进一步缩减App的大小。
- minifyEnable:
标识是否开启Proguard混淆,设置为true时需要同时设置Proguard配置文件名和规则,Proguard的作用不仅仅是混淆,它还具有压缩、优化等功能。它会遍历所有代码并找出没有引用到的代码,这些无用代码在生成最终Apk文件之前会被过滤掉。
buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }
- shrinkResources:
用来去除无用的resource文件,shrinkResources必须在minifyEnable为true的时候才能起作用。
buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } }
同时shrinkResources也需要慎重使用,因为某些资源可能是通过反射机制获取的,这类资源也可能会被过滤掉从而会导致在运行应用的时候会报Resource$NotFoundException异常,为了防止这种情况,可以在res/raw/下的一个叫keep.xml的文件中定义这些例外,一个简单的keep.xml的文件如下:
xml<?xml version="1.0" encoding="utf-8"?><resources xmlns:tools="http://schemas.android.com/tools" tools:keep="@layout/keep_me,@layout/main_*"/>
- resConfigs:
在开发中不可避免的会引入第三方函数库或者SDK,在不修改它们的前提下,不可避免的会引入很多我们不需要的资源,主要可以分为以下两种:
1). DPI目录:
由于Android支持的屏幕密度很多,所以我们可以根据自身需求剔除第三方函数库或者SDK中不需要的DPI目录或者文件。
2). 国际化文件:
我们引入的第三方函数库可能做了国际化适配,所以我们可以根据自身的APP的需求来将我们不需要的国际化文件给剔除掉。
android { ... defaultConfig { ... resConfigs "en","da","nl" resConfigs "hdpi","xhdpi","xxhdpi","xxxhdpi" }
- ndk.abiFilters:
在app/bulid.gradle文件中增加ndk.abiFilters配置,可以指定我们需要的ABI类型,从而可以过滤掉不需要的ABI类型的.so文件。
android { ... defaultConfig { ... ndk{ abiFilters "armeabi-v7a" ,"x86" } }
2.4 利用微信的资源混淆
微信资源混淆是通过直接修改resources.arsc文件达到资源文件名的混淆,同时利用7z深度压缩,大大减少了安装包体积,同时也增加了逼格,提升了反破解难度。