Andorid性能优化(四) 之 如何给Apk瘦身

1 前言

我们在日常开发过程中,随着版本的迭代、应用模块或功能的增多、老旧代码冗余、各种炫酷效果加入、大分辨率手机对图片的要求、图片不合理使用、滥用第三方库,等原因,应用安装包Apk文件也就逐渐越来越大了。虽然目前手机流量价格已经不像过去几年那么高了且WiFi覆盖环境也越来越多,手机性能和存储空间也没有过去那么的苛刻,一个安装包增加那么几M也不是什么大问题,但是这些并不是让我们可以忽略这个问题的理由。想想一个普通功能的应用如果因为安装包太大就会影响用户在选择时跟竞品对比从而处于劣势;包大也会跟下载时间、安装时间以及占用安间成正比,而且如果是因为代码量多、图片大和多导致的话还会引起应用本身的内存占用。所以看上去不痛不痒的几M大小,实际上这些也是产品体验应该去追求的一种优化。今天这篇文章我们就来看看导致应用安装包变大的情况和解决方法。

2 从何入手

Apk文件实际上就是一个zip包,所以我们可以查看到内部文件结构,一般地一个Apk包的结构如下图所示。

它的内部主要包含了以下文件:

assets                           包含一些db数据库文件、字体库、Json/Xml配置等不可编译的资源文件

lib                                  依赖的不同ABI类型的SO文件

res                                 XML、图片、音频,等编译过的资源文件

classes.dex                  包含了所写的Java代码经过编译后的class文件,一个或多个,取决于方法数是否超过65525

resources.arsc            编译之后的资源的映射关系配置信息,相当于资源索引表

META-INF                     存放签名相关信息

AndroidManifest.xml  用于配置App信息和四大组件信息的清单文件

所以,我们要对Apk进行瘦身,其实说来很简单的一句话,就应该从Java源代码和资源文件入手,删代码和资源、重构代码和资源、压缩代码和资源。

3 瘦身方案

3.1 减少代码量

一个应用中代码能简便简,代码量不旦影响安装包的大小,还会导致应用内存占用高(这个论点在前面文章《Andorid性能优化(一) 之 如何给应用进行内存优化》查看PSS中介绍过)。减少代码量可以从以下几个方面入手:

砍功能

砍功能是最直接减少代码量的做法。正视用户数据,效果不好的功能、不痛不痒的功能能砍就砍,一个应用使用简单比功能多要好。

删除老旧代码

如果明确不需要的功能不要因为舍不得而不忍心移除,以后再需要可以通过代码版本管理工具找回即可,或者在移除前自行进行备份好。

避免滥用第三方库

第三方库使用起来轻松快捷,但是同时也是一把双刃刀,一些比较简单的逻辑能自己开发便自己开发,尽量少去依赖别人写的库,这样也是有利于个人成长。而且有时候往往由于想使用一个小点逻辑而引用了一个重量级的库,那是得不常失。

公共代码提取

养成功能开发完后重构代码的习惯,尽量地复用公共代码可以减少代码的冗余,写得一手漂亮的代码应该是每位开发人员一直要追求的目标。

使用Android Lint工具

使用Android Lint工具删除没被使用的代码,包括import、变量、方法和类,等。关于Android Lint的使用我们在下面再介绍。

3.2 整理资源

资源是造成应用内存占用高和安装包变大的最直接原因,所以一定要正视资源的合理使用。来看看整理资源的办法:

压缩资源图片

压缩图片是最立竿见影的办法,目前比较流行使用https://tinypng.com上进行压缩图片,其效果还是很不错的。而且要一直压、反复压,压到肉眼能看得出来失真才罢手。

尽量少用图片

有些时候,我们需求中可能只需要比较简单渐变色或图形,那么不使用Bitmap,改用Android提供的Drawable也是可以的,Drawable常被用来作为View的背景使用。它一般都是通过XML来定义。又或者可以通过自义View的onDraw来绘制实现。这样做是既省内存又省空间。有时候在不得不用图时,先要考虑一下能否使用尺寸尽量小的图或使用.9图。

图片复用

如果仅方向不同的图片,可以只用一张,然后再利用RotateDrawable旋转,如: 

使用Android Lint工具

使用Android Lint工具还可以找出无用的、重复的资源,如:string、color、drawable,等。关于Android Lint的使用我们在下面再介绍。

简化图片效果

一张图片色彩越多图片文件就会越大,在可接受范围内,可以稍微去简化一些图片效果,如去掉一些边发光、渐变等效果。

尽量使用非透明图片

带透明效果的图片因为本身带有透明通道,所以会比非透明的图片大一些,所以如果在明确背景颜色又非多处不同背景使用情况下,可以考虑直接填充背景色不做透明。

帧动画改造

如下图,是用于等待的转菊花动画,原来是使用了帧动画来实现,但是这样就需要用到了16张图片:

其实,同样的效果完全可以改成属性动画+扇形遮罩来实现。这样就能节省使用了14张图片,能省下的空间可能是10倍:

图片拼接复用

图片也可以像代码一样复用,使用拼接方法,除了可以减少大图片的使用,还有利于后期扩展,像如下:

部分资源云端化

像一些非首次使用的库、配置,可考滤将其云端化,然后再找到合适的时机将其下拉。

善用字体库

一些常用的单色的图标,可以考虑将其转化成矢量图,以字体库的形式提供使用。

3.3 打包压缩

通过Gradle瘦身

minifyEnable

Gradle中提供了代码混淆机制,使用minifyEnable=true来启用。代码混淆是一个非常有用的功能,它不仅能使应用Apk包size变小,还可以让反编译的人不容易看明白我们的源代码逻辑从而增加分析难度。一般情况下,release模式编译的版本会启动混淆功能。

shrinkResources

Gradle中提供了自动清理未使用的资源的配置,使shrinkResources=true来启用。此配置要配合minifyEnable一起使用,因为先清理掉无用的代码后,这样一些无用的代码引用的资源才能被清理掉。

使用minifyEnableshrinkResources都存在一个同样的问题,那就是当代码中使用了反射去时,Android Gradle就区分不出来了,从而反射不出目类代码和误清理了被引用的资源,所以在使用上要注意配置好keep白名单。

resConfigs

Gradle中resConfigs属于PraductFlavor{}的一个方法,它可以让我们配置哪些类型的资源才被打到包中去。

更多关于Gradle的介绍请参考前面的Gradle系列文章《Android Gradle使用详解(三) 之 Android Gradle插件配置详解》

AndResGuard混淆资源

AndResGuard是一个资源混淆打包工具。它通过修改resources.arsc文件,从而可以混淆Apk包的资源文件路径(比如将res/drawable/welcome.png混淆为r/s/a.png),同样也能达到减少Apk包体积的目的。它的使用非常简单,也是需要在Gradle中进行配置即可。详细步骤可参考前面的Gradle系列文章中《Android Gradle使用详解(八) 之 使用AndResGuard混淆Apk包资源》

3.4 插件化

在应用中非首次使用到且是独立模块功能,可以考虑将其插件化,关于插件化的相关知识,可以参考前面的插件化系列文章《Android插件化原理和实践》

4 使用Android Lint为应用瘦身步骤

Android Lint 是有 Android SDK 提供的一种静态代码检测工具。它的源码集成在 Android SDK Tools 16 及更高的版本中,我们可以在项目目录下通过 ./gradlew lint 命令调用,也可以通过 Android Studio 的 【Analyze】->【Inspect Code】路径调用 Lint 检查。它可以帮助我们检查项目中存在的问题,让我们更有规范性的开发App。它检测出来的问题例如有这些:

  1. 布局性能,如:无用布局、嵌套太多、布局太多
  2. 国际化问题,xml文件中是否存在硬编码
  3. 没有使用到的资源、代码
  4. 不一致的数组大小
  5. 图标的问题,如:重复的图标,错误的大小
  6. 可用性问题
  7. 可能的bug
  8. 等等

笔者在这里通过在某个工程中使用了lint生成一份检测报告,如下图。在应用瘦身方面,我们暂时只需关注以下5大项问题:

问题1:Android>Lint>Performance展开后里面有Unused resources项,是表示无用的资源,包括图片、XML、string、colors、style,等。

问题2:Android>Lint>Usability>Icons展开后里面有两项:Duplicated icons under different namesIdentical bitmaps across various configurations。它们分别表示不同的名字,但相同的图片(MD5完全一样的图片,但有多张) 和 不同的规格使用了两张相同的图片(例如:在hdpi和xhdpi里使用了一样的图片)。

问题3:Declaration>redundancy展开后里面有两项:Empty method和Unused declaration。它们分别表示空方法 和 未使用的声明,包括变量、方法和类。

问题4:Imports展开后里面有Unused import项,表示无用imports。

           

问题5:XML展开后里面有Unused XML schema declaration项,表示未使用的XML schema声明。

以上列出的5大项问题,我们将其尽量地解决后一般都能看得出来瘦身效果了。特别提醒一下,Android Lint可以反复运行检测几遍效果会更好,因为像删除了无用的代码后再检测可能又会检测出与其关联的资源。

 

 

发布了106 篇原创文章 · 获赞 37 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/lyz_zyx/article/details/85841675