Android-Reduce APK Size

前言

译文:https://developer.android.com/topic/performance/reduce-apk-size.html#apk-structure
随之Android的快速发展,基于Android平台的应用,经过不断的产品迭代,功能增加,apk大小也随之越来越大。因此Google官方也推出了关于缩减APK文件大小的专题文章,网上也有很多参考资料,但是大部分也是根据官方文档,再结合实践给出一套自己的方案。本文主要以翻译为主,并以此为基础资料。

Reduce APK Size

缩减APK大小
用户经常会不愿意或者避免去下载那些看起来很大,特别是在一些新兴市场,当手机设备连接上常见的2G/3G网时,或手机流量使用是按字节收费的套餐。这篇文章将介绍如何减小apk文件大小,也许能让更多的用户下载你的应用。
(从目前的情况看,其实流量的收费已经很低了,现在的无线网络非常的发达,到处都是wi-fi)

理解APK文件结构

在讨论如何减小应用大小之前,理解应用APK文件的结构时很有帮助,很有必要的。APK文件实际上是一个ZIP压缩文件,包含了构成应用的所有文件。这些文件包括Java程序字节码文件,资源文件,一个包含被编译资源的文件。
APK文件包含以下目录:

  • META-INF/:包含CERT.SF和CERT.RSA签名文件,还有MANIFEST.MF文件
  • assets/:包含应用所有的资产资源,可以通过AssetManager进行访问
  • res/:包含所有不被编译进resources.arsc文件的所有资源
  • lib/:包含根据不同处理器架构编译的源代码,子目录包含不同架构的文件,像armeabi,armeabi-v7a,armeabi-v8a,x86,x86-64,还有mips

APK还包含一下文件:

  • resources.arsc:包含被编译的资源,包含res/values/下的所有xml文件内容。打包工具将xml文件内容抽取出来,编译成二进制表,并进行归档。这些内容包括样式和语言字符串等,也包括layout等资源的路径。
  • classes.dex:包含Dalvik/ART虚拟机能理解的字节码文件。
  • AndroidManifest.xml:Android的核心清单文件,文件中列出名称,版本,权限,相关库文件等。

减少资源数量和大小

APK大小直接影响了应用的加载速度,应用内存的占用量,以及用电量等。一个直接有效的方法就是减少APK包含的资源数量和大小。比如说,删除有效的资源,使用可缩放Drawable资源代替图片资源。这个部分将讨论多种方式来减少资源达到缩减APK大小的目的。

移除无效资源

使用Android Studio自带的Lint静态代码分析工具,可以检测res/文件夹下不再引用的资源。lint会发现潜在的无效资源,并列出警告信息。

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

注:lint并不扫描assets/目录,asset是通过发射或库文件的形式链接到应用,而且lint不会删除文件,只会警告他们列出的无效资源

在代码中引入的第三方库,也会存在无效资源。Gradle可以自动的移除这些无效资源,当在build.gradle构建脚本中开启shrinkResources。

android {
// Other settings

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

}

为了使用shrinkResources这个属性,必须开启代码压缩,在构建的过程中,混淆会首先移除无效的代码,但是会保留无效的资源,然后在移除无效的资源。

更多关于ProGuard和其他Android Studio提供的缩减APK大小的方法请查看,Shrink Your Code and Resource

Android Gradle 0.7+及以上,可以声明应用所支持的配置。Gradle通过resConfig,resConfigs以及默认的配置项将这些配置信息传递给构建系统。构建系统将不会把配置以为的相关资源放入APK文件中,从而达到缩减APK文件大小的目的。更多详情信息可以查看,Remove unused alternative resources(选择性的移除无效资源)

最小化库文件中的资源

在开发APP的过程中,我们经常会使用外部的库来提高应用的可用性和多样性。比如说,你会使用Android Support Library来提高应用的兼容性,或者使用Google Play Services来检索自动翻译应用中的文本。

如果一个库原本是设计用来当服务器或桌面应用的,可能会包含应用所不需要的对象和方法。为了只包含应用所需要的资源,可以编辑库文件如果正式运行对库文件修改。或者使用一个可替代的,更小的库满足所需的功能来加入应用。
注:ProGruard可以清除导入库中的无用代码,但是无法移除库文件中内部的依赖库

适配指定密度

Android支持大量的移动设备,包括各种屏幕密度。Android 4.4+,框架所支持的密度包括:ldpi, mdpi, tvdpi, hdpi, xhdpi, xxhdpi, xxxhdpi。虽然Android支持各种密度,但是并没有必要提高所有密度的资源文件。

当你意识到只有少部分用户使用指定分辨率的设备时,需要考虑是否需要将此分辨率的资源方式APK中。当没提供指定分辨率资源时,Android会自动对现有分辨率资源进行缩放来适配当前的密度。

如果应用只需要缩放的图片,可以只提供drawable-nodpi/一份图片,来节省更多的大小,推荐每个应用都至少提供xxdpi倍率的图片资源。更多屏幕大小与密度信息请查看,Screen Sizes and Densities.

减少动画帧数

逐帧动画会大幅度增加APK的大小,一个动画会被分解为多幅PNG图片,每一幅图片代表一帧。通过比如一个逐帧动画包含30帧,将动画减少至15帧,动画资源所占大小也将减小一倍。

使用绘制对象

有些图片不需要使用静态的图片资源,Android框架可以实时动态的绘制图片。Drawable对象使用在XML定义,只占用很少的空间。另外XML绘制对象可以产生单色的material design图片。

重用资源

可以通过一张图片得到多种资源变体,比如对该图片进行着色,绘制阴影,旋转等等。官方推荐的做法是,在运行时对图片进行自定义重用。这也是一种减少压缩包大小的方式。

使用代码渲染

通过代码对图片资源进行渲染,也可以减少相应的APK大小。

压缩PNG文件

aapt工具在构建的过程中会对/res/drawable下图片资源进行无损压缩。例如,aapt工具会将无需256位的真彩色PNG图片转换成8位调色板PNG图片,这样即保证了同样的图片质量又可以减少内存和文件大小。
不过aapt有以下限制:

  • 不会压缩assets下的图片资源
  • 需要使用256或者少量颜色的图片资源优化
  • 膨胀已经压缩的PNG图片。为了避免这个问题,可以在Gradle构建的过程中使用cruncherEnabled标志位来控制这个过程。

aaptOptions {
cruncherEnabled = false
}

压缩PNG和JPEG图片

在不降低PNG图片质量的情况下使用PNG压缩工具:pngcrush, pngquant, zopflipng等。上述工具都可以减小PNG文件大小而不影响图片质量。PNGCRUSH工具特别有效,通过遍历PNG过滤器和zlib参数进行压缩,并使用最佳组合来压缩图片,输出最优的压缩配置。

JPEG图片可以使用packJPEG工具进行压缩,不过JPEG本身就是有损压缩格式。

使用WebP文件格式

使用PNG和JPEG图片的资源都可以使用WebP格式进行替换,WebP即提高JPEG的有损压缩,也提高PNG的透明度通道,而且压缩效果都比两者要好。

使用WebP文件格式也有一些显著的缺点,首先,WebP存在兼容性问题,并不是Android所有版本都支持这个格式,Android 3.2 (API 13)以下即不支持;其次,而且系统需要花更多的时间来解码WebP文件。

注:目前谷歌应用市场上可下载的应用必须使用WebP作为应用的ICON,如果不是则不让上架,很强盗,也是对WebP的一种支持。

从Android Studio 2.3开始,可以使用Android Studio对BMP, PNG, JPEG,以及静态的GIF转换成WebP格式文件,详情可以查看Create WebP Images Using Android Studio

使用向量图

SVG矢量图
可以使用向量图形来创建分辨率无关的图标以及其他可缩放的媒体资源,使用该格式,可以极大的减少APK大小。向量图相对与Android中的VectorDrawable对象,使用向量绘制对象,可以仅仅使用100字节文件创建一张屏幕大小的图片。

然而,缩减大量空间资源后,也极大提高了渲染向量图的时间,图片越大,显示在屏幕上所需要的时间也就越多。所以考虑使用小图标使用向量图格式。更多详细信息请查看VectorDrawable,Working with Drawables

减小本地及Java代码

有多种办法来减少应用的代码量,比如使用框架,代码复用,重复利用面向对象Java语言特性,代码使用整体统一的样式。

移除由IDE自动生成的无效代码

确认那些由脚本自动生成的无效代码。例如,许多缓存工具会生成大量的方法和class文件,会让app成倍的增大。

移除枚举类型

一个简单的枚举类会给dex文件增加大概1.0~1.4KB的大小,对于复杂的系统还有共享库来讲,会快速的累加。如果可以,建议使用@IntDef注解和ProGuard移除枚举并转换成整型,这种转化保留了枚举类型的优势。

减小本地代码大小

如果应用中使用到了本地代码或Android NDK,可以通过优化代码来减小程序包大小。有两个有效的方法:1. 移除debug相关代码;2. 不提取本地库文件

移除debug符合相关代码

使用debug符合只是为了在应用处于开发状态并且还需要继续调试。使用Android NDK提供的arm-eabi-strip工具,来移除本地库文件中无用的debug代码,然后就可以编译release版本。

避免提取本地库文件

.so文件在apk中存储是不进行压缩的,通过在应用清单文件manifest文件中的标签节点中设置android:extractNativeLibs标志为false。通过这个标志位,可以阻止应用安装时PackageManager从apk中复制.so文件至文件系统,并且还能提供增量更新的优点。

维护多个精简的apk

应用会包含很多用户下载后不会用到的内容,比如地区和语言相关信息。为了创建一个用户最小下载大小的apk,可以将应用拆分成多个apk,由屏幕大小或CPU架构等元素来决定如何拆包。

当用户下载应用时,设备将会根据设备特点和配置,下载匹配的apk。通过这种方式,设备将不会下载哪些和设备无关的资源,比如说,用户设备是hdpi设备,将不会下载xxxhdpi资源。

更多关于分包的信息请查看Configuration APK Splits 和 Maintaining Multiple APKs.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值