前言

包大小的重要性已经不需要多说,包大小直接影响用户的下载,留存,甚至部分厂商预装强制要求必须小于一定的值。但是随着业务的迭代开发,应用会越来越大,安装包会不停的膨胀,因此包大小缩减是一个长期持续的治理过程。

  • 提升下载转化率,安装包越小,转化率越高。
  • 降低渠道推广成本。
  • 降低安装时间,文件拷贝、Library解压、编译ODEX、签名校验这些,包体积越大越耗时。
  • 降低运行时内存等等。

环境

  • Android Studio Arctic Fox | 2020.3.1 Patch 2
  • AGP 7.0
  • 项目地址:wanandroid_jetpack

优化前

  • 4.7MB,4.2MB是google play下载的大小,会有压缩。

除了AS自带的Analyzer之外,还有ApkChecker、ClassyShark等工具。

APK的组成

文件 描述
lib so文件,不同的cpu架构
res 编译后的资源文件,drawable、layout等
assets 应用程序的资源、字体、音频文件等
classes(n).dex dx编译后的java文件
META-INF 签名信息相关
resources.arsc 二进制资源文件
kotlin 编译后的kotlin文件
AndroidManifest.xml 清单文件

APK构建流程


这是官方新版的打包流程,虽然省略了一些步骤,但是大致的流程还是比较清晰的。
再次简化一下:

资源文件、Java文件 > dex文件 > APK

优化思路

APK本质是一个压缩文件,是打包后的产物,那可以作为切入点的阶段就是打包前、以及打包中。

  • 打包前,即减少打包的文件,比如无用的资源、代码;
  • 打包中,对打包中的产物进行压缩,比如资源文件、So文件;

关键词:减少、压缩。

常规操作

1.Lint检测无用资源文件

Analyze > Run Inspection by Name > Unused resources



检测结果:

确定无用删除即可。

注意:
因为lint是本地静态扫描,所以动态引用的资源文件并不会识别出来,也会出现在检测列表里。

2.Lint检测代码

Analyze > Inspect code


检测结果:

因为这个项目是用kotlin写的,所以直接看kotlin目录下的检测结果。

注意:
因为lint是本地静态扫描,所以反射、动态引用的class并不会识别出来,也会出现在检测列表里。

3.图片压缩

推荐使用tinypng在线压缩。

4.TinyPngPlugin

手动压缩毕竟不高效,可以使用TinyPngPlugin一键压缩。
plugins搜索TinyPng安装即可。(新版AS安装完plugin已经不需要重启了)

压缩结果:

9张图片,可以看到效果还是非常可观的。
如果图片多,效果更加明显。

经过上面的操作,包体积减小4%,这还只是一个4.7MB的APK而已。

5.WebP

那这9张图还能继续优化吗?
可以,WebP格式的体积更小,而已AS也提供了一键转换支持。

以ic_avatar.png为例:

ic_avatar.png 优化后
原始大小 113.09KB
TingPng压缩 36.85KB
WebP 8.66KB

可以看到,转WebP之后,较原始大小减少了近93%,恐怖如斯~

6.开启混淆

minifyEnabled true,默认启用R8代码缩减功能。

    buildTypes {release {minifyEnabled trueproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}

慎用R8,因为:

R8 会忽略试图修改默认优化行为的所有 ProGuard 规则,例如 -optimizations 和 - optimizationpasses。

可以开启混淆,而不使用R8。

android.enableR8=false
android.enableR8.libraries=false

混淆参考:Android混淆从入门到精通

7.缩减资源

shrinkResources true

假如有一些资源文件不确定还用不用,也不敢删,或者不确定需求是否会变更,所以先留着,那这种情况怎么办呢?
可以使用shrinkResources来缩减资源。

    buildTypes {debug {minifyEnabled false}release {shrinkResources trueminifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'}}

要配合混淆minifyEnabled一起使用才行,原理也很简单,代码移除之后,引用的资源也就变成无用资源了,才可以进一步缩减。

8.so文件缩减

比如集成了一个三方的直播或者浏览器,可能会提供很多so文件,起初可能是一股脑的copy进项目,但并不一定都用的到。
比如各种cpu架构的so:

app/build/intermediates/cmake/universal/release/obj/
├── armeabi-v7a/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
├── arm64-v8a/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
├── x86/
│   ├── libgameengine.so
│   ├── libothercode.so
│   └── libvideocodec.so
└── x86_64/├── libgameengine.so├── libothercode.so└── libvideocodec.so

目前市面上的手机cpu都是arm架构的,所以保留arm的一种即可(定制的除外),armeabi-v7aarmeabi都可,其他直接删除。

android {defaultConfig {ndk {abiFilters 'armeabi-v7a'}}
}

如果开发需要模拟器调试,就加上x86的架构,正式包记得去掉,或者在local.properties中用变量控制一下。

这块如果之前没有优化过,而又有很多so文件的话,或许可以减少30%以上,恐怖如斯!

9.移除未使用的备用资源


很多出海的应用会做国际化,但也适配不了这么多的语言。
除了自己app的之外,还有一些官方的、三方的,可以统一配置支持的语言。

    defaultConfig {resConfigs("en","zh","zh-rCN")}

资源文件同理

    defaultConfig {resConfigs("xxhdpi","xxxhdpi")}

10.小结

针对上面的操作做个小结,看看目前效果如何。

2MB,包体积减少57%,恐怖如斯!

如果是大型项目,收益非常可观。

author:yechaoa

进阶操作

上面只是一些常规操作,下面看一些进阶操作。

1.resources.arsc资源混淆

资源混淆就是将原本冗长的资源路径变短,例如将res/drawable/wechat变为r/d/a。
开源工具AndResGuard。

2.移除无用的三方库

引入之后未使用的,或者是功能下架之后未移除的。

3.功能重复的三方库整合

比如glide和picasso,都是图片库,保留其一即可。

4.ReDex

dex文件是打包中的产物,redex是facebook开源的分包优化方案。
可以参考:ReDex。

5.so动态加载

前面已经做了so文件缩减,但是可能so文件占比还是比较大,可以考虑除了首次启动外的so文件做动态下发。
也就是插件化的思想,按需加载,但是收益很大的同时,风险也很大,有很多case需要考虑到,比如下载时机、网络环境、线程进程,加载失败是否有降级策略等等。

可以参考facebook开源的SoLoader。

6.插件化

按需加载,收益越大风险越大,风险同上。

极致操作

那如果我想做到极致,还有哪些骚操作呢,ok,继续。

1.原生改用H5或小程序等方案

有些功能可能原生做就显得太重,比如各种促销活动,需要加载各种大图,原生既重又不够动态化,这个时候H5是一种很好的替代方案。
但是如果你原本就不支持H5或者小程序的话,接入这种能力可能反而会加大包体积,做好对比。

2.砍功能

有些功能可能想的很美好,但上线之后收益并不大,是否需要重新思考价值点,最好找到数据依托,再跟产品打架。

3.修改三方库的源码,不需要的代码剔除

比如引入了一个功能很齐全的三方库utils,但实际只用到几个,对源码进行抽取也能减少包体积,同时还能减少网络下载的编译时间。
弊端就是升级成本较大。

4.图片网络化

即把图片上传到服务器,通过动态下载的方式减少包体积,弊端就是首次加载的时候依赖网络环境,对加载速度、流量需要做一个平衡。
图片可以预加载,但是流量消耗是无法避免了,如果比较在意流量指标,需要权衡了。

5.DebugItem

DebugItem 里面主要包含两种信息:

  • 调试的信息。函数的参数变量和所有的局部变量。
  • 排查问题的信息。所有的指令集行号和源文件行号的对应关系。

去除debug信息与行号信息,如果不是极致,不推荐。
可以参考支付宝的这篇 支付宝 App 构建优化解析:Android 包大小极致压缩。

6.R Field内联

内联R Field可以解决R Field过多导致MultiDex 65536的问题,而这一步骤对代码瘦身能够起到明显的效果。

美团代码片段:

ctBehaviors.each { CtBehavior ctBehavior ->if (!ctBehavior.isEmpty()) {try {ctBehavior.instrument(new ExprEditor() {@Overridepublic void edit(FieldAccess f) {try {def fieldClassName = JavassistUtils.getClassNameFromCtClass(f.getCtClass())if (shouldInlineRField(className, fieldClassName) && f.isReader()) {def temp = fieldClassName.substring(fieldClassName.indexOf(ANDROID_RESOURCE_R_FLAG) + ANDROID_RESOURCE_R_FLAG.length())def fieldName = f.fieldNamedef key = "${temp}.${fieldName}"if (resourceSymbols.containsKey(key)) {Object obj = resourceSymbols.get(key)try {if (obj instanceof Integer) {int value = ((Integer) obj).intValue()f.replace("\$_=${value};")} else if (obj instanceof Integer[]) {def obj2 = ((Integer[]) obj)StringBuilder stringBuilder = new StringBuilder()for (int index = 0; index < obj2.length; ++index) {stringBuilder.append(obj2[index].intValue())if (index != obj2.length - 1) {stringBuilder.append(",")}}f.replace("\$_ = new int[]{${stringBuilder.toString()}};")} else {throw new GradleException("Unknown ResourceSymbols Type!")}} catch (NotFoundException e) {throw new GradleException(e.message)} catch (CannotCompileException e) {throw new GradleException(e.message)}} else {throw new GradleException("******** InlineRFieldTask unprocessed ${className}, ${fieldClassName}, ${f.fieldName}, ${key}")}}} catch (NotFoundException e) {}}})} catch (CannotCompileException e) {}}
}

同时可以参考字节开源的shrink-r-plugin,还有滴滴开源的booster。

7.图片着色器

针对同图不同色的处理,可以使用tint,比如原本是一个黑色的返回icon,现在另一个页面要用白色了,就不需要两张图了,而是使用tint来修改为白色即可。

         <ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_back_black"android:tint="@android:color/white" />

8.减少ENUM的使用

每减少一个ENUM可以减少大约1.0到1.4 KB的大小。

包体积监控

包体积监控应该作为发布流程的一个环节,最好是做到平台化、流程化,否则很难持续,没几个版本包体积又涨上来了。

大致思想:当前版本与上一个版本的包大小做对比,超过200KB需要审批。临时审批需要给出后续优化方案等等。

参考文档

  • Improve your code with lint checks
  • Shrink, obfuscate, and optimize your app
  • Android App包瘦身优化实践
  • ReDex
  • SoLoader
  • 支付宝 App 构建优化解析:Android 包大小极致压缩
  • AndResGuard
  • 深入探索 Android 包体积优化
  • Android开发高手课包体积优化

Android包体积优化(常规、进阶、极致)相关推荐

  1. 深入探索 Android 包体积优化(匠心制作-下)

    前言 成为一名优秀的Android开发,需要一份完备的 知识体系,在这里,让我们一起成长为自己所想的那样~. 在 Android 性能优化的知识体系当中,包体积优化一直被排在优先级比较低的位置,从而导 ...

  2. 抖音Android包体积优化探索:从Class字节码入手精简DEX体积

    前言 众所周知,应用安装包的体积会十分影响用户的应用下载速度和安装速度.据 GoolgePlay 平台对外发布相关的包大小对转化率影响的数据,我们可以看到随着包大小的增加,安装转化率总体呈下降的趋势. ...

  3. Android包体积优化上篇- 资源混淆优化

    导读:什么时候进行包体积优化?一般在app初创期时,由于业务代码较少,包体积也不大,相应这个时候对包体积的优化收益也较少.当业务逐渐成熟功能,迭代逐渐变多,包体积也会逐渐增加. 增加包体积主要影响如下 ...

  4. 抖音 Android 包体积优化探索:资源二进制格式的极致精简

    动手点关注 干货不迷路 

  5. 深入理解android 包体积优化,给apk瘦身全部技巧

    前言 随着iphone13p最大内存放大到了1T,大内存手机的时代悄然降临,在android里面,三星也有,罗老师几年前说:如果我告诉你们我们在做1T的手机,你们可能以为我疯了. 看看现在,估计未来会 ...

  6. 【保姆级】包体积优化教程

    市面上有很多优化方案,但是都没有一个完整的链路体系,现在它来了,本文将带你进阶新高度,不管是面试.绩效KPI,还是汇报宣讲,都能让你游刃有余! 前置必读: Android包体积优化(常规.进阶.极致) ...

  7. 超好的包体积优化教程,不仅仅是优化

    作者:yechaoa 市面上有很多优化方案,但是都没有一个完整的链路体系,现在它来了,本文将带你进阶新高度,不管是面试.绩效KPI,还是汇报宣讲,都能让你游刃有余! 前置必读: Android包体积优 ...

  8. 性能优化之三——包体积优化大战

    博客结构 1.优化意义 2.分析工具 1.APK Analys 2.重要参数诠释 3.编包流程 4.优化战法 1.常规战法 1.清理无用资源 1.Lint工具 2.开启shrinkResources去 ...

  9. 包体积优化·工具论·初识包体积优化

    " [小木箱成长营]包体积优化系列文章: 包体积优化 · 实战论 · 怎么做包体积优化? 做好能晋升吗? 能涨多少钱? 包体积优化 · 方法论 · 揭开包体积优化神秘面纱 " 一. ...

最新文章

  1. spark mysql 驱动_spark读取mysql数据库的驱动问题
  2. linux虚拟网络设备--eth, tap/tun, veth-pair(九)
  3. golang的错误汇总
  4. 15年考的全国计算机应用技术,(2015年全国专业技术人员计算机应用能力考试.doc...
  5. android 通知历史,Android 4.3人性新功能:查看通知历史
  6. 前端学习(571):margin负值下的两栏自适应
  7. 汇编实现的memcpy和memset
  8. C#字典类型转URL参数字符串
  9. jQuery.access的作用
  10. project 2013使用记录
  11. ER Studio 使用笔记
  12. php极光短信接口接入
  13. Cox比例风险模型与R实现
  14. 163邮箱给gmail邮箱发邮件,gmail邮箱收不到
  15. 计算机处理器i3 i5,realme Book笔记本高清渲染图曝光 配置上搭载11代酷睿i3/i5处理器...
  16. GAMES104实录 | 游戏引擎导论(上)
  17. 现在投资最校园跑腿可行吗?
  18. 史上最强!PC时代的20位英雄
  19. win2d 渐变颜色
  20. SQL:查找某个班级的人数并按班级人数多少进行排列,查找各班年龄最小的女生的班级号,学号,姓名,出生日期并按班级号升序排列

热门文章

  1. bzoj4084 [Sdoi2015]bigyration题解
  2. AVB简介--第二篇:gPTP简介
  3. 如何在没有联网的情况下使用maven本地仓库进行开发
  4. VS code 安装Source Code Pro字体
  5. B1192 [HNOI2006]超级英雄Hero 二分图匹配
  6. 用css3实现图片左右翻转
  7. FPGA 十进制 转化为二进制
  8. 微信小程序 uChars统计图
  9. 360wifi在linux系统如何使用,在树莓派上使用360WIFI(也适用于小米、百度、腾讯WIFI)...
  10. TensorFlow2 手把手教你实现自定义层