您的位置:首页 > 其它

APK瘦身指南

2016-12-15 21:47 120 查看
用户一般会不会在应用市场上下载那些看起来很大的App,尤其是当他们使用2G或3G网络或者是按流量付费的时候。因此这篇文章将讲述如何减小APK的大小,从而让更多的用户来下载你的应用。

了解APK文件的结构

在探讨如何减小App大小之前,有必要先弄清楚APK文件的结构。APK实质上是一个ZIP压缩文件,它包含了构成App的所有文件,如Java类文件,资源文件,以及编译后的资源文件等。

一个APK包含以下几个文件目录:

META-INF/:包含CERT.SF及CERT.RSA签名文件以及MANIFEST.MF。

assets/:包含App的资源,这些资源文件可通过AssetManager获取。

res/:包含了不会被编译到resources.arsc中的资源。

lib:包含了特定于处理器软件层的已编译的代码。该文件夹中针对不同处理器平台架构提供不同子文件夹,如armeabi、armeabi-v7、arm64-v8a、x86、x86_64以及mips。

一个APK还包含了以下文件,其中,只有AndroidManifest.xml是强制性的。

resources.arsc:包含了编译的资源,如res/values/文件夹中的xml文件将会被编译到这里。打包工具会将xml文件编译为二进制格式,包括strings及styles以及某些资源的路径信息,如布局文件以及图片资源。

classes.dex:包含可被Dalvik或ART虚拟机执行的DEX文件。

AndroidManifest.xml:包含了Android的核心配置文件,该文件配置了应用的名称、版本、访问权限以及引用的类文件等信息。此文件也是被编译为二进制格式。

减少资源数量及大小

APK的大小会影响应用的加载速度、内存占用以及电量消耗。一个简单的减小APK的方法是减少它所用到的资源数量和大小。尤其是我们可以移除App中不再使用的资源,还可以使用Drawable来替代图片文件。这一节将讨论上述方法及其他几种方案来减小App中的资源以达到APK瘦身的目的。

移除无用资源

使用Android Studio提供的静态代码分析工具——lint,可以检测到res/文件夹中未被你的代码引用的资源。一旦lint工具发现了潜在的未使用的资源,就会打印出如下信息:

res/layout/preferences.xml: Warning: The resource R.layout.preferences appears
to be unused [UnusedResources]


注意:lint工具并不会扫描assets/文件夹、以及通过反射或library引用的资源;另外lint并不会移除资源,只是提醒它们的存在。

App中添加的一些Library可能包含无用的资源,如果我们在build.gradle文件中配置了
shrinkResources
,那么Gradle可以帮助我们删除这些资源文件。

android {
// Other settings

buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}


为了使用shrinkResources,需要允许代码压缩,在应用的构建过程中,首先ProGuard会移除无用代码,但会保留未使用的资源,然后Gradle再移除未使用的资源。

更多关于ProGuard及其他Android Studio提供的APK压缩方法,可参考Shrink Your Code and Resources

减小第三方库的大小

开发一个Android应用时,会经常用到第三方库来实现各种各样的功能,例如,可能会使用Android Support Library来兼容老的设备以提升用户体验,或者可能使用Google Play Service实现App的文本自动翻译功能。

如果一个库是为服务端或桌面应用设计的,它可能包含了很多App中用不到的对象和方法。为了只引入App所用到的部分,如果该库的许可允许修改,那么我们可以修改精简该库;或者使用其他专门针对移动端的可替代库来实现App功能。

注意:ProGuard可以移除library中的一些无用代码,但无法删除library中大的内部依赖。

仅支持特定屏幕密度

Android支持一系列设备,包括各种不同的屏幕分辨率。Android 4.4及更高的版本,支持众多屏幕密度,如ldpi、mdpi、tvdpi、hdpi、xhdpi、xxhdpi、xxxhdpi。尽管Android支持上述所有屏幕密度,但我们不需要为所有密度提供图片资源。

如果你知道某个分辨率的设备使用者占比很小,则可以考虑是否还要为其提供针对性的资源。如果我们不提供某个分辨率的图片资源,Android系统会自动将已存在的资源缩放以适配该屏幕密度。

如果应用仅需要可缩放的图片,可以使用drawable-nodpi/以节省更多空间,同时推荐为每个App至少配置一个xxhdpi图片文件夹。

减少动画的帧数

帧动画会显著增加APK的大小,因为帧动画一般会被分离成多张图片,每张图片代表动画的一帧。

动画中每添加一帧,意味着APK将增加一张图片数量。

使用Drawable

一些图片不需要静态图片资源,系统可以在运行时动态绘制。Drawable在APK中只占用很小的空间,另外用XML表示的Drawable对象可以生成兼容Material Design指南的单色图。

资源重用

对于着色、阴影、旋转等效果,可以只使用一张独立的图片即可。这里建议重用同一套资源,在需要的时候再进行自定义处理。

Android提供了一些列的实用工具来改变资源的颜色,如使用android:tint或tintMode属性(API level 21+),对于低于Android 5.0的版本,则可以使用ColorFilter类。

对于图片旋转的需求,下面代码片段提供了一个示例:简单地将原始图片选装180度,从而将一个箭头icon从“展开”状态变为“收起”状态:

<?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" />


使用代码渲染

可以使用程序代码来渲染图片以减小APK大小,因为如果用代码来实现的话,就不需要在APK中存储图片了。

Crunch PNG Files

在构建过程中,aapt工具可以对res/drawable/中的图片进行无损优化,如aapt可使用调色板将小于256色的真彩色PNG图片转换为8-bit的PNG。这样做可以在不影响图片质量的情况下减小内存占用。

需要注意aapt有以下局限性:

aapt工具不能压缩assets/文件夹中的PNG文件

aapt工具只能优化那些不超过256色的图片文件

aapt工具可能inflate被压缩过的PNG文件,为了禁止此功能,可以在Gradle中使用cruncherEnabled标志:

aaptOptions {
cruncherEnabled = false
}


压缩PNG与JPEG文件

可以在不影响图片质量的情况下对PNG文件进行压缩,常用工具有 pngcrushpngquant,或者zopflipng。这些工具都可以减少PNG文件大小,同时保持图像质量。

pngcrush是特别有效的工具,它会遍历PNG过滤器和zlib(紧缩)参数,使用每个过滤器及参数的组合来压缩图像,然后选择能够产生最小压缩输出的配置。

对于JPEG文件,可以使用类似 packJPG的工具来将JPEG压缩到更紧凑的形式。

使用WebP文件格式

除了使用PNG及JPEG文件外,还可以使用 WebP图片格式来作为替代。WebP拥有JPEG的无损压缩以及PNG的透明度特性,同时可以提供更优于JPEG及PNG的压缩效果。

使用WebP文件格式有几个值得注意的缺陷,第一,低于Android3.2(API level 13)的系统不支持WebP,第二,使用WebP将花费比PNG文件更多的解码时间。

注意:Google Play只接受应用图标为PNG格式的应用,不能使用其他文件格式,如果打算通过Google Play来分发应用,则不可使用JPEG或WebP格式的应用图标。

使用矢量图

可以使用矢量图来创建分辨率无关的icon或者可缩放的多媒体,使用矢量图可以极大地减小APK的大小。矢量图在Android中表现为VectorDrawable对象,使用VectorDrawable,100字节的大小就可以创建一个清晰的屏幕大小的图片。

然而,使用VectorDrawable,系统需要更多的时间来渲染,如果图片较大,则需要更长的时间才能显示到屏幕上。因此,最好是在展示小图片时考虑使用矢量图。

减小Native与Java代码的大小

可以使用以下几种方法来减小Java代码与Native代码的大小。

移除不必要的生成代码

请务必了解自动生成的代码会占用多大空间,例如,许多协议缓冲工具会产生过多的方法和类,它可以占用双倍或三倍于App的大小。

移除枚举

单个枚举可以使App的classes.dex文件增加1到1.4KB的大小,由于系统的复杂性及共享库的使用,这种增加累计起来将会很可观。如果可能,考虑使用@IntDef注解或者使用ProGuard将注解转换为整型,这种类型转换可以保持枚举类型的安全性。

减少本地二进制文件的大小

如果应用使用到本地代码及Android NDK,我们可以通过优化代码来减小应用的大小。两种有用的技术可以删除调试符号而不是提取本地库。

删除调试符号

在应用的开发与调试阶段,使用调试符号是有意义。可以使用Android NDK提供的arm-eabi-strip工具来移除本地库中不必要的调试符号。移除之后,我们可以编译应用的release版本。

避免提取本地库

将未压缩的.so文件添加到APK中,在manifest配置文件的中将android:extractNativeLibs设为false。做了上述配置后,在应用安装时,PackageManager将不会把.so文件从APK中拷贝到文件系统,这样做也有额外的好处,可以使App的增量更新变得更小。

维护多个专用APK

用户下载了你的App,但很可能有些内容用户不会用到,如地区及语言信息。为了让用户得到最小化的下载,我们可以根据一些因素,如屏幕尺寸或对GPU的支持来将我们的App分化成多个App。

当用户下载App时,可以根据用户的设备信息与配置下载对应的APK,因此,该设备将不会收到与此设备本身支持的特性不匹配的资源要素。例如,用户设备只支持hdpi,所以这些设备不需要为高密度设备所准备的xxxhdpi资源。

官方原文:Reduce APK Size
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  APK瘦身