首页 > 代码库 > 缩小apk的大小
缩小apk的大小
原文地址:https://developer.android.com/topic/performance/reduce-apk-size.html
减小APK的体积
This lesson teaches you to
- Understand the APK Structure
- Reduce Resource Count and Size
- Reduce Native and Java Code
- Maintain Multiple Lean APKs
You should also read
- Shrink Your Code and Resources
如果你的app看起来很大,用户通常避免下载,特别是在很多新兴的国家,人们使用2G和3G网络接入因特网,和按流量计费。这篇文章介绍如何减小app的体积,这会帮助更多的用户来下载你的app。
理解apk的结构
在讨论如何减小你的app的apk大小之前,理解一个apk的结构是很有帮助的。一个apk文件,是一个zip文件,包含java class文件,资源文件,和编译的文件资源。
一个apk包含下列文件:
META-INF/
: 包含CERT.SF
和CERT.RSA
签名文件, 也包括MANIFEST.MF
配置文件.assets/
: 包含一个app的引用资源文件,用AssetManager 检索res/
: 包含那些没有被编译到resources.arsc 的资源
.lib/
: 编译好的代码。有子文件,代表平台类型,如armeabi
,armeabi-v7a
,arm64-v8a
,x86
,x86_64
, andmips
.
一个apk也包含下面这些文件。 下面只有 AndroidManifest.xml
必须会有.
resources.arsc
: 包含编译的资源文件,主要是res/values/下面的XML文件。打包工具从xml里面提炼内容,编译成二进制的形式。这些内容包括字符,样式,也包含那些不在resources.arsc里面的文件,如图片和布局文件的路径。classes.dex
: 包含被虚拟机Dalvik和ART识别的,以Dex格式存在的classes编译文件。AndroidManifest.xml
: android核心配置文件。配置文件列出了app的名称,版本,权利,和相关的包。xml格式。
减少资源的数量和体积
apk体积的大小,对app加载的速度,占用的内存,消耗的电力有很大的影响。让apk变小的,很常见很有效的一点是,减少资源的数量和体积。特别是,减少app不再使用的资源,使用放大的Drawable对象代替图片文件。这节讨论几种方法,较少app的资源,来减少app超出的体积。
减少无用的资源
lint工具
, 一个android studio的静态代码分析器,删除你的res/
文件中代码不再引用的资源.当lint工具
在工程中发现一部分未使用的资源,会打印下列信息.
res/layout/preferences.xml: Warning: The resource R.layout.preferences appears to be unused [UnusedResources]
Note: lint
工具不扫描assets/
文件, assets that are referenced via reflection, or library files that you‘ve linked to your app. Also, it doesn‘t remove resources; it only alerts you to their presence.
Libraries 你添加的lib可能包含没有用的资源. 在 app的build.gradle 文件添加 shrinkResources == true 时,
Gradle 会自动减少这些资源.
android { // Other settings buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile(‘proguard-android.txt‘), ‘proguard-rules.pro‘ } } }
用这个shrinkResources
, 你必须确保你的代码shrinking. 在编译过程中,第一个 ProGuard 属性会删除无用的code , 但是会留下无用的资源。然后,Gradle 会删除这些无用的资源.
要了解 ProGuard 更多信息,和其他的android studio帮助减小apk大小的方法,请看Shrink Your Code and Resources.
在android gradle 0.7 及以上版本,你可以申明你app支持的配置。Gradle使用这些选项【resConfig
and resConfigs
flavors and the defaultConfig
option】来通过编译系统。编译系统可以防止不受配置支持的资源出现在apk文件,以此来减小apk的大小。此功能的更多信息,请看Remove unused alternative resources.
使用最小化资源的库
当我们开发android app,通常会使用第三方的库来实现功能和效率. 例如,你可能用到Android Support Library来改善在旧设备上的用户体验, 或者你可以使用Google Play Services实现app里面的文字的自动翻译。
如果一个库是为了服务器,和电脑设计,它可能包含很多app不需要的对象。如果许可修改这个库,你应该编辑这个库,以仅仅包含app需要使用的部分。你还可以使用手机友好的库加入你的app,作为一种替换方法。
Note: ProGuard can clean up some unnecessary code imported with a library, but it can‘t remove a library‘s large internal dependencies.
只支持特定的密度
Android支持多种密度的设备。在Android 4.4 (api level 19)及以上版本, the framework 支持多种密度:ldpi
,mdpi
,tvdpi
,hdpi,
xhdpi
,xxhdpi
and xxxhdpi
. 尽管Android支持所有这些密度,你没有必要为每种密度导出资源。
如果你知道某种密度的用户比较少,考虑是否需要这些密度打包到你的app。如果你不包含这种密度的资源,android会自动将现有的其他密度的资源通过缩放显示.
如果你的app之需要缩放的图片,你会通过拥有一中drawable-nodpi/图片来节省更多的空间。我们确保每个app都只会扫包含xxhdpi这种。
更多屏幕密度,请看 Screen Sizes and Densities.
减少动画帧
逐帧动画,会非常明显的增加apk的大小。图1显示了一个逐帧动画的例子,在一个文件夹中包含多个不同的PNG。每张图片就是动画的一帧。
你添加一帧,就在apk里多一张图片。图1,这个图片动画大概每秒30张左右。如果用每秒15张代替,这个动画仅需要一般的帧数。
Figure 1. Frame by frame animations stored as resources.
使用Drawable对象
有写图片,不需要一个静态的图片资源。framework可以在运行时,动态地画出图片。Drawable
对象(<shape>
in XML) 会占用apk极少的空间. 另外, XML Drawable
对象 会生成如何 material design 原则的单色图片。
复用资源
通一张图片的多种形式,如着色,阴影,旋转等,你可以使用一张单独的资源.然而,我们建议你重用相同的一组资源,在运行时根据需要定制它们。
Androdi提供多种工具来改变组件的颜色,5.0或更高的通过 android:tint 和 tintmode ,或者更低版本使用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" />
代码渲染
你也可以通过程序渲染图片来减少apk的大小。程序渲染可以释放空间,因为i不需要在apk里面存储。
紧缩PNG文件
aapt工具可以在编译过程中,无损地优化res/drawable/的图片资源。例如,aapt 工具
通过一个调色板 可以把一个真彩色的PNG转变成一个8bit的PNG,不再需要256颜色。这意味同等质量,但更小的内存占用.
记住 aapt
有以下局限:
aapt
工具不能缩小asset/下面的 PNG- aapt工具缩小图片文件,需要它们use 256或更少颜色
aapt工具可能会加压已经压缩的PNG图片。为了避免这一点,你要是在Gradle中使用
cruncherEnabled禁止PNG文件的这个过程。
aaptOptions { cruncherEnabled = false }
压缩PNG and JPEG 文件
你可以使用pngcrush, pngquant, or zopflipn等工具,在不损失图片质量的情况下,减少PNG的文件大小。所有这些工具都可以在保护图片质量的情况下,减少PNG文件的大小。
pngcrush工具尤其有效:这个工具遍历PNG过滤器和zlib(缩小)参数,使用过滤器和参数的组合压缩图像。然后选择配置收益率最小的压缩输出。
对于JPEG文件,您可以使用packJPG工具,它可以压缩JPEG文件成一个紧凑的形式。
使用WebP文件格式
替换PNG和JPEG文件,你可以使用WebP文件格式。WebP 格式兼有 JPEG的有损压缩,和 PNG的透明度,但是比单独的JPEG或PNG更好的压缩。
使用WebP有一些明显的缺陷。第一,android 3.2 以下不支持。第二,和PNG相比,系统解码该格式的图片需要更多的时间。
Note: 谷歌市场只接收app启动图标为PNG的apk。不支持其他格式的图片作为启动icon。
你可以使用 Android Studio 将现有的 BMP, JPG, PNG or GIF 图片换成WebP格式.更多信息,请看 Create WebP Images Using Android Studio.
使用向量图片
你可以使用矢量图形 创建分辨率无关的图标和其他可伸缩的媒体。使用这些图形可以大大减少你的APK大小。矢量图在在Android 中用VectorDrawable对象表示。VectorDrawable对象,一个100字节的文件可以生成一个锋利的屏幕图像的大小。
然而,系统呈现每个VectorDrawable对象需要大量的时间,显示到屏幕的图像更大,花费的时间更长。因此,只有当显示小图像,考虑使用这些矢量图形。
For more information on working with VectorDrawable
objects, see Working with Drawables.
减少本地和java代码
有下面几种方法.
移除产生的不必要的代码
确保明白自动产生的任何代码的footprint。譬如,很多protocol buffer工具会产生过多的方法,会成倍,甚至三倍地增加代码大小。
移除枚举
一个单独的enum会增加app中calsses.dex文件大约1.0到1.4KB的大小。对于复杂系统或共享库,这些添加可以迅速积累。如果可能的话,可以考虑使用@IntDef注释和ProGuard 移除枚举,并将它们转换为整数。这类型转换将保存所有的枚举类型的安全的好处。
减少本地库的大小
如果你的app只用本地代码和android NDK, 你可以优化代码来减少apk的大小. 两种有用的技术:去除调试符号,和 避免提取本地库。
去除调试符号
如果你的程序还在开发中,仍然需要debug,请使用debug符号。使用Android NDK提供的 arm-eabi-strip
工具从本地库中移除不需要的debug符号。然后,你编译release版本.
避免提取本地库
保存 apk中未压缩的so文件,和在app的manifest文件中的<application>下面设置android:extractNativeLibs
为false.这可以避免 在安装的时候, PackageManager
从apk中拷贝so到文件系统 ,并且这样做的一个额外的好处是,增量更新的时候,增量包更小。
维护多个精品apk
你的apk会包含一些用户从下载apk之后永远不会使用的内容,如地区,语言信息。为你的用户创建一个精简的下载,你能够可以将app分为几个apk;由一些不同的因素如屏幕大小,是否支持GPU 纹理等区别.
当一个用户下载你的app时,他们的设备接收正确的apk,这个apk基于他们的设备特性和设置。这样,设备不需要接收哪些不需要的资源。譬如,如果一个用户有一个hdpi的设备,他们不需要xxxhdpi的资源,这个资源是更高密度的设备显示所需要的。
更多信息,请看 Configure APK Splits and Maintaining Multiple APKs.
缩小apk的大小