【腾讯Bugly干货分享】Android减包 - 减少APK大小

标签: 腾讯 bugly 干货 | 发表时间:2017-05-04 20:39 | 作者:Tencent_Bugly
出处:http://blog.csdn.net

本文是对Google官方文档 Reduce APK Size 的翻译,点击“阅读原文”可以查看英文原文。

译者简介:damonxia(夏正冬),天天P图Android工程师

用户经常会避免下载看起来体积较大的应用,特别是在不稳定的2G、3G网络或者在以字节付费的网络。这篇文章描述了怎样减少你的APK大小,这会让更多的用户愿意下载你的应用。

理解APK的结构

在讨论怎样减少应用大小之前,先了解APK的结构是有用的。一个APK文件就是ZIP包,其中包含了组成你的应用的所有文件,比如Java类文件,资源文件,和一个包含被编译资源的文件。

一个APK包含了以下目录:

  • META-INF/: 包含CERT.SF和CERT.RSA签名文件,也包含了MANIFEST.MF文件。(译注:校验这个APK是否被人改动过)
  • assets/: 包含了应用的资源,这些资源能够通过AssetManager对象获得。
  • res/: 包含了没被被编译到resources.arsc的资源。
  • lib/: 包含了针对处理器层面的被编译的代码。这个目录针对每个平台类型都有一个子目录,比如armeabi, armeabi-v7a, arm64-v8a, x86, x86_64和mips。

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

  • resources.arsc: 包含了被编译的资源。该文件包含了 res/values目录的所有配置的XML内容。打包工具将XML内容编译成二进制形式并压缩。这些内容包含了语言字符串和styles,还包含了那些内容虽然不直接存储在resources.arsc文件中,但是给定了该内容的路径,比如布局文件和图片。
  • classes.dex: 包含了能被Dalvik/Art虚拟机理解的DEX文件格式的类。
  • AndroidManifest.xml: 包含了主要的Android配置文件。这个文件列出了应用名称、版本、访问权限、引用的库文件。该文件使用二进制XML格式存储。(译注:该文件还能看到应用的minSdkVersion, targetSdkVersion等信息)

译注:使用APK Analyzer能够清晰地看出以上文件的内容,具体请看:使用APK Analyzer分析你的APK。

减少资源个数和尺寸

APK的大小会影响应用加载的速度,使用的内存大小,消耗的电量大小。一个最简单的缩小APK大小的方式是减少资源的个数和大小。特别地,你能移除应用中不再使用的资源,你也能使用可缩放的Drawable对象代替图片文件。这节讨论一些通过减少资源从而减少APK大小的方法。

译注:减少资源个数和缩小资源大小的效果是很显著的,比如有一天发现我组里的项目中还包含了旧版本的引导页视频(1.5M),一下就就减少了1.5M,想想为了减少1.5M你得删多少代码才能办到。

移除不使用的资源

lint是Android Studio中的一个静态代码分析工具,检测在“res/”目录中你的代码没有引用的资源。当lint工具发现了项目中潜在的未使用的资源,它会打印以下类似信息:

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

注意:lint工具不会扫描“asset/”目录,这个目录是通过反射引用的资源,或者链接到应用中的库文件。还有,lint不会移除资源,只会发出警告。

被引用的库中可能会包含没使用的资源。如果你在build.gradle文件中启用shrinkResources,则Gradle能自动移除这些资源。

为了使用shrinkResources,你必须要启用代码混淆。在构建过程中,首先proguard移除了未使用的代码,然后gradle移除未使用的资源。

译注:lint工具还能够检查出未使用的类、类中未使用的方法或变量。

更多关于通过代码混淆和其他方式减包,请看Shrink Your Code and Resources。

在Gradle插件0.7或更高版本,你能申明应用支持的配置。Gradle通过传递resConfigs和defaultConfig给构建系统,构建系统会防止不支持的配置出现在APK中,从而减少APK大小。更多信息请看Remove unused alternative resources。

译注:在hello world工程里,resConfigs配置为“zh”和不配置resConfigs,resources.arsc文件相差了80K。

最小化第三方库中资源的使用

当开发Android应用时,你经常使用第三方库提升应用的可用性和灵活性。比如,你引用Android Support Library提升旧设备的用户体验,或者使用Google Play服务实现文字自动翻译。

如果一个第三方库原本是为服务器或普通电脑设计,会引入许多不需要的对象和方法。为了只引入应用需要的库中的那部分,你可以编辑库文件(如果库的license允许你这么做)。你也能使用另外的针对手机的实现同样功能的库。

注意:代码混淆能清除库中不被使用的代码,但是他不能移除库的大量内部依赖。

只支持部分屏幕密度

Android支持很多设备集,其中包含了各种不同的屏幕密度。在Android 4.4及更高版本,框架支持不同的密度:ldpi, mdpi, tvdpi, hdpi, xhdpi, xxhdpi和xxxhdpi。尽管Android支持所有这些屏幕密度,但你不需要为每个密度都配置相应的资源。

如果你知道某种特定屏幕密度已经很少有用户使用了,那么你可以考虑是否需要为这个屏幕密度配置资源。如果你不包含针对特定屏幕密度的资源,那么Android会自动缩放原本针对其他密度的已有资源。

如果你的应用只需要缩放的图片,你甚至可以把图片存放在drawable-nodpi目录,从而节省更多空间。我们推荐每个应用都应该至少包含xxhdpi的图片。

更多关于屏幕密度的信息,请看Screen Sizes and Densities。

减少动画帧数

使用帧动画会大大增加APK的大小。图1显示了目录中构成帧动画的多个PNG文件。每个图片都是动画的一帧。

对于加入动画的每帧,你都增加了APK中图片的个数。图1中,帧动画的帧率是30 FPS。如果帧率降到15 FPS,图片数量将减少一半。

图1:帧动画的每一帧图片。

译注:还有一个常见的减包方案是删除帧动画中重复的图片资源,比如第1帧和第3帧的图片一样,那么只保留一个。

使用Drawable对象

一些图片不需要静态的图片资源,框架能在运行时动态地绘制图像。Drawable对象(XML的)只需要占用APK中的一点空间。另外,XML形式的Drawable对象能够产生遵循Material Design设计规范的图像。

重用资源

你能包含一张图片的很多变种,比如染色、阴影、旋转的版本。但是,我们推荐在运行时复用一张图片来定制化他们。

Android提供了很多方式改变资源的颜色。对于Android 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大小。代码方式绘制图像不需要任何空间因为你不再需要在APK中存储图像文件。

压缩PNG文件

AAPT工具能够在构建过程中通过无损压缩优化res/drawable/中的图片资源。比如aapt工具能将需要颜色少于256色的PNG变为8位PNG图,这样能够在保证图片质量的同时减少内存使用。

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

  • aapt工具不会压缩asset目录的PNG文件。
  • 通过aapt的优化,图片文件会使用少于256色。
  • aapt工具可能会影响已经被压缩过的PNG文件。为了防止这种情况,你可以在gradle文件中设置cruncherEnabled为false禁用aapt对PNG的压缩。
  aaptOptions {
    cruncherEnabled = false
}

译注:建议把cruncherEnabled设为false,然后通过tinypng手工压缩PNG图片。

压缩PNG和JPEG文件

你能使用一些工具(比如pngcrush, pngquant, zopflipng)在不降低图像质量的前提下减少PNG文件大小。所有这些工具都能保留图像质量的情况下减少PNG文件大小。

pngcrush工具特别有效:这个工具通过迭代png过滤器和zlib参数,使用每种过滤器和参数的组合压缩图像,并选择最小的那个作为最后的输出。

对于JPEG文件,能使用packJPG压缩JPEG文件。

译注:guetzli是Google最近推出的JPEG编码器,官方宣称相同图片质量时,比libjpeg生成的图片小20–30%。

使用WebP文件格式

你也能使用WebP文件格式存储图片而不是PNG或者JPEG。WebP格式是有损压缩(像JPEG)且有透明通道(像PNG),且压缩率高于JPEG或PNG。

使用WebP文件格式也有一些缺点。第一,低于Android 3.2的版本不支持WebP,第二,WebP的解码时间比PNG长。

注意:Google Play的APK的应用启动图标只能使用PNG格式,而不支持其他格式。

在Android Studio中,能将BMP,JPG,PNG或者静态GIF图片转换成WebP格式。更多信息,请看Create WebP Images Using Android Studio。

使用向量图

你能使用向量图去创建一个分辨率无关的图标。使用向量图能够显著减少APK大小。在Android中向量图是以VectorDrawable对象形式存在的。使用VectorDrawable对象,一个100B的文件能生成一个屏幕大小的清晰图片。

但是,系统需要很长时间渲染VectorDrawable对象,更大的图片需要更长的时间显示在屏幕上。因此只有小图片才考虑使用向量图。

更多关于VectorDrawable对象的信息,请看Working with Drawables。

减少Native和Java代码

有许多方法能够减少Java和Native的代码量。

减少不必要的生成代码

确保理解任何自动生成的代码。比如,许多protocol buffer工具生成了过多的方法和类,这会让你的应用大小翻倍。

移除枚举

一个枚举能让classes.dex文件增加1–1.4K。枚举的加入会快速增加应用体积。我们可以使用@IntDef注解和Proguard代替枚举,它能提供和枚举一样的类型安全转换。

减少Native库的大小

如果你的应用使用了Native代码和Android NDK,你也能通过优化代码减少应用体积,这里介绍的两个技巧是删除调试符号和避免抽取Native库。

移除调试符号

如果应用在开发中并且仍需要调试,那么我们能理解使用调试符号。使用Android NDK提供的arm-eabi-strip工具,能从Native库中删除不必要的调试符号,之后你再编译release包。

避免抽取Native库

在APK中存储未压缩的so文件,并且在Manifest文件的中设置android:extractNativeLibs为false,这会防止在安装时PackageManager将APK中的so文件拷贝到文件系统,避免这种拷贝会让应用在做增量更新时的更新包更小。

维持多个小的APK包

你的APK会包含用户下载了但从未使用的内容,比如地区或语言信息(译注:比如我是中国人,我就不会用到其他语种的资源)。为了给用户创建小的下载包,你能把你的应用拆分成多个APK,这些APK的差别在于一些因素(比如屏幕大小或者GPU纹理支持)。

当一个用户下载了应用,设备根据自身的特性和设置获取正确的APK。这种方式能够让设备不获取设备不需要的资源。比如,如果设备是hdpi的,那么他就不需要xxxhdpi的资源。

更多信息请看Configure APK Splits和Maintaining Multiple APKs。


更多精彩内容欢迎关注 腾讯 Bugly的微信公众账号:

腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的情况以及解决方案。智能合并功能帮助开发同学把每天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同学定位到出问题的代码行,实时上报可以在发布后快速的了解应用的质量情况,适配最新的 iOS, Android 官方操作系统,鹅厂的工程师都在使用,快来加入我们吧!

作者:Tencent_Bugly 发表于2017/5/4 12:39:22 原文链接
阅读:179 评论:0 查看评论

相关 [腾讯 bugly 干货] 推荐:

【腾讯Bugly干货分享】Android减包 - 减少APK大小

- - CSDN博客移动开发推荐文章
本文是对Google官方文档 Reduce APK Size 的翻译,点击“阅读原文”可以查看英文原文. 译者简介:damonxia(夏正冬),天天P图Android工程师. 用户经常会避免下载看起来体积较大的应用,特别是在不稳定的2G、3G网络或者在以字节付费的网络. 这篇文章描述了怎样减少你的APK大小,这会让更多的用户愿意下载你的应用.

【腾讯Bugly干货分享】WebP原理和Android支持现状介绍

- - IT瘾-geek
目前网络中图片仍然是占用流量较大的一部分,对于移动端更是如此,因此,如何在保证图片视觉不失真前提下缩小体积,对于节省带宽和电池电量十分重要. 然而目前对于JPEG、PNG、GIF等常用图片格式的优化已几乎达到极致,因此Google于2010年提出了一种新的图片压缩格式 — WebP,给图片的优化提供了新的可能.

腾讯高管一篇满是干货的演讲:访问美国互联网公司后的感悟

- - i黑马
用户体验设计(UXD)是当今互联网和移动互联网行业最火热的设计概念,其发源于美国软件行业现在又在中国蓬勃发展,其中的从业者肯定非常关心目前用户体验领域在国际上的发展现状,国外最新的设计趋势与团队情况,我们又该从这些先进的设计方法与流程中学习到什么. 5月25日下午,【腾讯大讲堂·移动互联网】系列讲座第8期,邀请到了腾讯移动互联网设计中心总监周陟,带着他最近到访美国各大互联网公司的设计考察经历,既有具体的设计团队交流见闻,也有几款APP制定团队访问行程的秘籍,在深圳贝特咖啡馆进行了长达三个小时的分享…….

腾讯的内涵图

- keeno - 阿禅日记
2011年5月31日10:33,腾讯QQ 浏览器首页的截图如下:. 内涵关键词:释放、aiww、64. 1小时后,腾讯将图片替换掉了. 对这位如此有内涵的经理或编辑或设计师致敬. © Jason Ng for 阿禅日记, |. 不要用中国手机号来找回Gmail密码.

腾讯电商帝国

- 以外 - 互联网的那点事...
腾讯宏伟的电子商务战略开始逐渐浮出水面. 5月30日,腾讯正式对电子商务业务的内部组织架构进行重组,机构更加复杂全面的电子商务业务线取代了原来的电子商务部,同时进行近十位中、高层管理人员的职位变动及内部人员的调整. 同时,腾讯一直在电商领域全面出击,通过投资进行战略布局. 从今年年初至今,腾讯以超乎想象的速度战略入股了数家电子商务企业,包括已经对外公 布的好乐买、易讯、F团以及数宗尚未对外公布的收购案.

腾讯CMEM的PHP扩展

- duyue - 平凡的世界
最近公司在做相关的业务,由于Memcached协议缺少返回码,为了保证业务数据的安全性,不得已只好自己写个扩展来实现需求. 基于memcache扩展的2.2.6的稳定版开发而来. 代码已经开源,有需要的朋友请拿走,License是PHP License,请自觉遵守. 项目主页:http://code.google.com/p/cmem/.

腾讯:变局前夜

- - 互联网的那点事
8条业务线,20座城市,20000名员工. 做为中国最大的互联网公司之一,腾讯正面临着前所未有的管理挑战. 2012年4月12日,网易发布的一则公告引起了业界的强烈反响. 网易称,旗下重要产品——新闻客户端遭到腾讯抄袭. 腾讯当天上架地新闻iPhone客户端2.0版本在产品整体布局、跟帖页面、图片浏览页面的设计几乎与网易新闻客户端的相关功能和设计完全一致.

抄袭,腾讯 和 产品

- - 黄小肆依旧在理性与感性里挣扎
作者:陈皓 很早就想写这篇文章了,只是想法比较零碎,所以一直没有成文,这两天觉得思考得比较成熟了一些,所以把我的这些想法整理下来,欢迎大家一起和我讨论. 首先,先表达我的立场,我对抄袭的立场持BS和痛恨的态度,尤其是 那些C2C的网站,痛恨这些国外有什么就山寨什么的做法,尤其是那些连界面都不改,像素级的抄袭,连CSS和img都是一样的,更甚者,连图片都链接到抄袭源的网站去了,连源代码都抄的行为,比如: 腾讯抄新浪的代码, 新浪抄twitter的源码.

腾讯的产业长征

- - 今日话题 - 雪球
腾讯的2B问题,最近引发了无数讨论. 把这些讨论总结一下,无外乎就是三个问题:B端市场的产业升级+技术革命,腾讯到底还要不要参与. 刚刚,腾讯时隔六年进行了重大战略升级与公司架构调整,调整后的腾讯,保留了原有的企业发展事业群(CDG)、互动娱乐事业群(IEG)、技术工程事业群(TEG)、微信事业群(WXG);新成立了云与智慧产业事业群(CSIG)和平台与内容事业群(PCG).