APK瘦身最佳实践

在开始对APK进行正式的减肥之前,我们先来了解一下APK包的构成,这样才好对症下药嘛。知己知彼方能百战不殆。

APK文件内容速揽

我们可以通过 unzip <apkname>.apk 命令实现对apk的解压(你也可以直接将<apkname>.apk更名为<apkname>.zip后直接通过解压软件解压)。解压后,我们就会得到一个文件夹了,里面包含了:

 
 
  1. AndroidManifest.xml
  2. /assets
  3. classes.dex
  4. classes2.dex
  5. ...
  6. /lib
  7. /arm64-v8a
  8. /armeabi-v7a
  9. /mips
  10. /x86
  11. /x86_64
  12. /META-INF
  13. CERT.RSA
  14. CERT.SF
  15. MANIFEST.MF
  16. /res
  17. /anim
  18. ...
  19. resources.arsc

各个文件和目录的作用是什么呢?

文件/目录 作用
AndroidManifest.xml 清单文件,列出了应用的名称,版本,权限等信息。
assets 配置文件,放置一些本地资源,例如本地html,可以通过使用AssetManager检索。
classes.dex, classes2.dex 编译后的字节码文件,能够被Dalvik/ART理解。
lib 存放特定平台使用的编译后的.so文件,每一个子文件夹对应一个特定的平台,例如armeabiarmeabi-v7aarm64-v8ax86x86_64, and mips.
META-NIF 包含 CERT.RSACERT.SFMANIFEST.MF, 存放的签名信息,用于保证系统的安全性和APK文件的完整性。
res 存放没有被编译到 resources.arsc文件中的资源文件。
resouces.arsc 编译后的二进制资源文件。存放 res/values/ 目录下的所有XML内容。打包工具对XML内容进行提取,编译为二进制,并进行分类,其中,XML内容包含了不同语言的strings和styles,同时还包含没有被直接打包至 resources.arsc 文件的其他文件的路径,例如布局文件和图片文件。

OK,既然我们已经了解了APK的各个组成部分,那么我们就可以针对下面的三个组成部分,采取逐个击破的方式,达到缩减APK体积的目的:

Java代码

我们可以使用Proguard,在编译时对Java代码进行混淆,优化和压缩。Proguard对代码进行遍历,然后剔除其中未被使用的冗余的代码,并对类,属性,接口等进行重命名,从而达到瘦身的目的。

我们可以在 build.gradle 文件中配置Proguard。

 
 
  1. buildTypes {
  2. release {
  3. minifyEnabled true
  4. proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
  5. }
  6. }

在未使用Proguard之前,我们的APK体积达到了13.9M。

开启Proguard后,APK的体积缩减到了10.1M。可见,效果还是很明显的。

除此之外,微信的工程师还开源了一个项目,可以直接对APK进行处理,缩小体积。具体的使用方法:https://github.com/shwenzhang/AndResGuard。

资源文件

Lint

由于Proguard只对Java代码起作用,对于资源文件,它就无能为力了。这个时候,Lint就派上用场了。Lint是一个静态的代码分析器,我们可以通过在 Android Studio -> Analyze -> Inspect code... , 选择范围即可开始就检查。

Lint在检查完成后,会提供一份详细的资源文件清单,并且将没有用到的资源在 UnusedResources:Unused resources 区域。只要我们没有通过反射使用这些资源,就可以放心的删掉它们了。

下面是我根据lint的提示,剔除了部分无用资源后,APK的体积:

Notice:需要注意的是,Lint并不会扫描 assets 目录,所以最好还是手动的检查一下 assets 目录下是否有未被使用的文件吧。

我们还可以通过配置 shrinkResources 来移除未使用的资源。不过,使用 shrinkResources 必须开启代码混淆。在处理过程中,ProGuard 会移除未被使用的代码,但是不会移除资源。而开启 shrinkResources 后,Gradle就会移除资源了。

下面为开启 shrinkResources 后APK体积的变化:

又缩小了一点点。

图片压缩

对于资源文件的优化,其实占大头的还是图片。Android打包本身会对png进行无损压缩,在不那么影响图片显示效果的情况下,对图片进行有损压缩对apk体积的减小还是非常可观的。

我们先使用TinyPng对项目中四张比较大的图片进行压缩,可以看出,效果还是非常不错的。

使用TinyPng后,我们还可以将图片转换为 WebP 格式,进一步缩小图片的体积。不过需要注意的是,WebP格式仅适用于Android 4.0+版本,如果你的应用需要兼容Android 2.3,那么需要额外的引入 .so 文件,apk的体积自然也会增加。所以,根据你的需求,权衡利弊吧。

在 Android Studio 中,选定需要转换的图片,然后右键鼠标,即可在菜单底部看到 Convert to WebP 的选项了,然后就可以进行转换的操作。

经过上面的处理,我们的App体积来到了9.6M。

矢量图

如果你的项目中使用 appcompat 兼容包,并且版本在23.2以上,那么,使用矢量图或许是个不错的选择。矢量图和分辨率无关,理论上支持任何级别的缩放。以一张常用的 点赞 图标为例,在 Android中使用 Vector 矢量图,大小为:

而它对应的xxxhdpi的png格式,大小为:

效果显而易见,但是这也并不是意味着,我们就可以将所有的图片替换为 矢量图 了 。我们来看一看ic_favorite_black_24dp.xml 的源代码:

 
 
  1. <vector xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:width="24dp"
  3. android:height="24dp"
  4. android:viewportWidth="24.0"
  5. android:viewportHeight="24.0">
  6. <path
  7. android:fillColor="#FF000000"
  8. android:pathData="M12,21.35l-1.45,-1.32C5.4,15.36 2,12.28 2,8.5 2,5.42 4.42,3 7.5,3c1.74,0 3.41,0.81 4.5,2.09C13.09,3.81 14.76,3 16.5,3 19.58,3 22,5.42 22,8.5c0,3.78 -3.4,6.86 -8.55,11.54L12,21.35z"/>
  9. </vector>

正如你所见,vector的颜色是单一的颜色,所以,vector 适用于图标等颜色单一的图片,如果是颜色比较复杂,那么vector很明显就不合适了。

使用JPG

对于非透明的大图,JPG格式将会比PNG格式的大小有显著的优势,虽然不是绝对的,但是通常会减小到一半都不止。在启动页,活动页等之类的大图展示区采用JPG将是非常明智的选择。

对于图片的使用,Google的建议,简单来说就是:VD->WebP->Png->JPG

  • 如果是纯色的icon,那么用svg
  • 如果是两种以上颜色的icon,用webp
  • 如果webp无法达到效果,选择png
  • 如果图片没有alpha通道,可以考虑jpg
复用图片

项目中我们还可能遇到图片内容相同,仅仅是颜色不同的情况。这个时候我们就可以使用Android提供的着色来完成,而不用提供好几套图片。例如在Android 5.0+上我们可以使用 android:tint 和 android:tintMode,在低版本中可以使用ColorFilter

对于那些内容颜色等都相同,只是方向不同的图片,我们可以只保留一中方向的,其他方向的图片通过代码实现。例如我们可以对上面提到的 ic_favorite_black_24dp 进行翻转。创建一个 drawable

 
 
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <rotate xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:drawable="@drawable/ic_favorite_black_24dp"
  4. android:fromDegrees="180"
  5. android:pivotX="50%"
  6. android:pivotY="50%"
  7. android:toDegrees="180" />

虽然Android设备的分辨率非常的多,但这并不代表着我们需要为每一种分辨率都准备一套资源。在显示差异不大的情况下,我们可以尽量复用一套图片资源,一套布局,然后再考虑特定屏幕密度。

语言资源

说完了图片,我们还要来说说语言资源。对于大多数的应用,并不需要支持几十种的国际化。使用Gradle,对语言资源进行配置,也可以达到应用瘦身的目的。例如,我们的应用如果只需要支持中文和英语:

 
 
  1. android {
  2. defaultConfig {
  3. ...
  4. resConfigs "en", "zh"
  5. // 支持分辨率
  6. resConfigs "nodpi", "hdpi", "xhdpi", "xxhdpi", "xxxhdpi"
  7. }
  8. }

Native Code

如果你的App使用到了Native code,在不影响功能的前提下,可以考虑去除部分平台对应的代码,例如移除对 armeabi、mips的支持,

 
 
  1. android {
  2. ...
  3. splits {
  4. abi {
  5. enable true
  6. reset()
  7. include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
  8. universalApk true
  9. }
  10. }
  11. }

当然,如果是特别大的原生库,我们还可以通过网络,从云端获取,而不直接打包在APK中。

其他

  • 别忘了最简单,也最容易忽视的,去除重复的依赖,或者是引用更加轻量级的库,也可以达到apk瘦身的效果。
  • 在Release版本中,去除那些只会在debug时才会出现的代码。
  • 对于那些使用频率很小的文件或者是图片,可以存放到云端后,通过网络加载。

结语

相对小的体积能够在用户安装前就给用户留下不错的印象,但是,这不并代表着我们可以为了追求APK体积的小巧而过度的牺牲用户体验。权衡利弊后,选择合适的,才是最重要的。

项目完整地址: Espresso - Espresso is an express delivery tracking app designed with Material Design style, built on MVP(Model-View-Presenter) architecture with RxJava2, Retrofit2, Realm database and ZXing.

如果你觉得文章不错的话,请点个赞吧。有其他问题,可以通过以下方式联系我:

Zhihu: https://www.zhihu.com/people/kirin-momo/

Slack: https://androiddevsslack.slack.com

Weibo: http://weibo.com/u/5313690193

Medium: https://medium.com/@TonnyL

Twitter: https://twitter.com/TonnyLZTL

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业设计,基于SpringBoot+Vue+MySQL开发的影城管理系统,源码+数据库+论文答辩+毕业论文+视频演示 随着现在网络的快速发展,网上管理系统也逐渐快速发展起来,网上管理模式很快融入到了许多生活之中,随之就产生了“小徐影城管理系统”,这样就让小徐影城管理系统更加方便简单。 对于本小徐影城管理系统的设计来说,系统开发主要是采用java语言技术,在整个系统的设计中应用MySQL数据库来完成数据存储,具体根据小徐影城管理系统的现状来进行开发的,具体根据现实的需求来实现小徐影城管理系统网络化的管理,各类信息有序地进行存储,进入小徐影城管理系统页面之后,方可开始操作主控界面,主要功能包括管理员:首页、个人中心、用户管理、电影类型管理、放映厅管理、电影信息管理、购票统计管理、系统管理、订单管理,用户前台;首页、电影信息、电影资讯、个人中心、后台管理、在线客服等功能。 本论文主要讲述了小徐影城管理系统开发背景,该系统它主要是对需求分析和功能需求做了介绍,并且对系统做了详细的测试和总结。具体从业务流程、数据库设计和系统结构等多方面的问题。望能利用先进的计算机技术和网络技术来改变目前的小徐影城管理系统状况,提高管理效率。 关键词:小徐影城管理系统;Spring Boot框架,MySQL数据库
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值