Android包体积优化

背景:

 1.为什么要做包体积优化

在2018年的Google I/O,Google透露了Google Play上安装包体积与下载转化率的关系图。


下载转化率:一个 100MB 的应用,用户即使点了下载,也可能因为网络速度慢、突然反悔下载失败。对于一个 10MB 的应用,用户点了下载之后,在犹豫要不要下的时候已经下载完了。但是正如上图的数据,安装包大小与转化率的关系是非常微妙的。(10MB 跟 15MB 可能差距不大,但是 10MB 跟 40MB 的差距还是非常明显的)

推广成本:一般来说,包体积对渠道推广和厂商预装的单价会有非常大的影响。特别是厂商预装,这主要是因为厂商留给预装应用的总空间是有限的。如果你的包体积非常大,那就会影响厂商预装其他应用。还有一些街边推广需要靠数据流量来下载的场景,更是直接影响用户的下载意向。

2. 包体积与应用性能的关系

安装时长:文件拷贝、Library 解压、编译 ODEX、签名校验等,甚至包括一些混编的工程来说,初步解压转化就要占据很长的时间

运行内存RAM资源越多,加载到内存里的东西越多,占据内存越多,就容易越卡顿

物理内存ROM对于一些32G,64G用户来说,可能装不了几个大型的app

二、我们大致能做些什么?

简单来说可以分为三部分:

1:业务梳理优化,随着时间的堆积,尤其一些大型应用,业务线不断增多,功能不断增多,代码量就上去了,所以要定期清理一些旧的功能,不用的,效益不好的,等等,各个维度来降低业务堆积。

2: 转变开发模式,配合一些混编模式,h5,小程序分担一些不必要的需求等方式,来减少原生代码堆积。

3:  技术方式瘦身,结合实际情况,打包特性等操作,来做瘦身。我们重点说一下这一部分。

三、瘦身之前先认识apk

 1apk是由哪几项组成的


 大致是由

dex代码相关

resassets:资源相关

libso相关

meta-inf应用的签名校验信息相关

 2、分析apk的几种方式

大致有几种方式:

apk说到底是一个压缩包,如果实在不想使用任何工具,可以把后缀改为.zip,然后直接解压

一个比较官方的方式apktoolapktool

使用AS,在菜单栏Build>Analyze apk ,比较清晰的看到结构和每个文件的大小

nibledroid 这个是一个比较完善的工具,(我没有实践,感兴趣的小伙伴可以去康康)

android-classyshark 是一个二进制分析工具,可以清晰看到每个包名下代码占比

四、开始优化

从apk结构可以看出,dex和lib是apk大小的“大头”

先说so的优化方式:

 soAndroid上的动态链接库,在我们Android应用开发过程中,有时候Java代码不能满足需求,比如一些 加解密算法或者音视频编解码功能,这个时候就必须要通过C或者是C++来实现,之后生成So文件提供给Java层来调用,在生成So文件的时候就需要考虑生成市面上不同手机CPU架构的文件。目前,Android一共 支持7种不同类型的 CPU 架构,比如常见的armeabiarmeabi-v7aarm64-v8aX86等等。理论上来说,对应架构的 CPU 它的执行效率是最高的,但是这样会导致 lib 目录下会多存放了各个平台架构的 So 文件,所以App的体积自然也就更大了。

现在市场支持64位,32位两种系统的apk包,打包的时候会拆包进行打包。也是为了合理的包体积优化考虑。之前是只打入64位的,64位可以兼容32位,只是效率会差点,现在应用市场支持分包了,很不错。

1: 常见的处理方式,拆包,根据手机架构和位数来动态适配

2: so动态下发,该方案比较彻底,对包体积优化比较友好,但是兜底方案不好制定,会存在因为下载失败导致的某些功能暂时不可用

dex主要优化方式:

1: 安卓ProGuard(混淆)

提到混淆,大家都想到的是打包时混淆,其实远不止此,混淆大概有四个作用:

1-1:压缩(Shrink): 侦测并移除代码中无用的类、字段、方法和特性 1-2:优化(Optimize): 对字节码进行优化,移除无用的指令 1-3:混淆(Obfuscate): 使用a,b,c,d这样简短而无意义的名称,对类、字段和方法进行重命名 1-4:预检(Preverify): 在Java平台上对处理后的代码进行预检



代码混淆形式一般有三种:

1:将代码中的各个元素,比如类、函数、变量的名字改变成无意义的名字。例如将 hasValue 转换成单 个的字母 a。这样,反编译阅读的人就无法通过名字来猜测用途。

2:重写代码中的部分逻辑,将它变成功能上等价,但是又难以理解的形式。比如它会改变循环的指令、结构体。

3:打乱代码的格式,比如多加一些空格或删除空格,或者将一行代码写成多行,将多行代码改成一行。

混淆规则:

https://www.jianshu.com/p/d5ee2f1f977f

ps:混淆本来就是为了节约字节码站位和反编译风险,所以尽量不要keep *,这样就等于无效混淆了。

优化(dontoptimize)-dontoptimize关闭优化

压缩(dontshrink)- dontshrink关闭压缩

混淆(dontobfuscate)-dontobfuscate 关闭混淆

这里多说一下:

混淆非常重要大家都已经知道了,那么细看一下gradle中的配置,其中有一句是:

proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro', 'mpProguard.cfg'

x0; 大家有没有想过proguard-rules.pro这个是自己的文件,那么getDefaultProguardFile是什么,它在哪里?它的作用是什么?

其实该getDefaultProguardFile文件所在目录是在android/sdk/tools/proguard/,是Android sdk 为我们提供的一些Android内置的一些混淆规则,可以理解为是通用配置。当你没有额外定义混淆规则时,就按通用混淆规则进行混淆。

其次说一下mapping文件,这个文件也非常重要,这个文件是混淆后的输出文件,如果遇到崩溃情况资源找不到情况,可以由该文件找到资源和混淆后字母的对应关系:


这里有个小tips:如果一个类没有被引用,是不会参与混淆的。mapping里找不到映射关系。


像我们这种大体量的app,光mapping文件就一百多M了

2:andResGuard 资源混淆

原生安卓的混淆主要是针对于代码,而工具AndResGuard主要是针对资源

x0; 3:第三方库

第三方库,随着项目逐渐发展,引入的第三方库越来越多,这时候需要排查是否有功能相同的第三方库,比如图片的第三方库,比较流行的有glide,Fresco等,还有处理Json的也容易重复,所以我们需要排查第三方库,避免引入相同功能的第三方库。其次,对于一些比较大的第三方,功能比较齐全,有时候我们可能就只用它的一部分功能,可以进行源码依赖,二次代码剥离,但是同时也要面对版本管理问题。

4:移除无用代码,无用类,无用资源

对于删除代码通常有两个问题:

1: 业务代码越来越多

2: 代码越多越不敢删

其实如果可以确定无用了,也就敢删除了,所以如何确定无用就非常重要:

1:业务层面,产品直接说,确定是功能下线,关联代码直接删除

2:技术手段筛选无用代码: 

2-1: 统计可以打点的所有page,捞取apk里所有page,取差值,就是真正的无用页面

2-2: Lint扫描, ,扫描无用资源, 扫描无用代码,Lint的弊端是不完全准确,因为lint的无用资源和无用代码是割裂开进行扫描的,尤其针对无用代码中引用的无用资源,一般情况下扫描不到,所以需要反复扫描多次。我个人很少遇到误删的情况,但是还是需要反复确认一下比较安全。

2-3: 有一些算法,加载文件处理成String,扫描文件名是否在其他文件中引用,算法也是同样有弊端。

3: 低pv页面转web,低pv,参考业务埋点数据统计。

ps: 工具simian扫描重复代码的,感兴趣的小伙伴可以看一下。

额外:对于代码编码方向,尽量少用枚举 不要拿google源码中也有大量枚举来杠,每减少一个 enum 可以减少大约 1.0 1.4 KB 的大小,这个是已经被论证了的。所以尽量少用。

5: 资源文件少配置


语言包只配置英文

图片只载入一套drawable-xxhdpi

6: 打包再次压缩(滴滴插件)

 滴滴的出的bosster 是针对打包过程中二次资源整理,重复资源去重,压缩,整理resources.arsc文件等处理的比较彻底,添了google对于无用资源处理方式(不移除用一个空白文件替代)

booster

像这个体量的app,用booster保守估计可以再压缩5-10M左右,还是比较可观的。

7:图片优化

在一些大型app中,图片资源也是重中之重,所以控制好图片资源也对包体积优化有不可或缺的贡献。

图片优化大概分几个方向:

UI层面:尽量使用原生自带的样式,或者尽可能统一UI样式,一些图片close,back等常用图片能统一使用

图片压缩,导入包内前用压缩工具处理压缩

安卓原生尽量转webp图片使用,这里需要注意不是每个png转webp后都会体积下降,注意下即可

一些纯色icon尽量用矢量图VectorDrawable,VectorDrawable》webp》png》jpg

8:避免产生Java access方法

java access方法是,为了提供内部类和外部类直接调用掉对方私有成员变量,又不违反java的封装性规范,Java在编译时期自动会生成 package 可见性的静态方法。因为我们没有引入ASM,加上该优化方式收益并不是很大,所以大家了解一下就好了。

https://mp.weixin.qq.com/s/ZHisCVjO_ZrtvvEWBYUQFQ

9:插件化

插件化开发能有效的大幅度降低包体积,一些独立的模块变为插件化开发,从服务器拉取下来家加载,能有效的降低包体积。

build目录下,这里每个目录可以结合上一篇gradle里面task来看,这里就是每个task后输出的对应目录对应的内容,最后根据这些内容进行打包。


参考文档:

https://time.geekbang.org/column/article/81483

http://t.zoukankan.com/sihaixuan-p-10978222.html


此篇文章由于脱敏问题,缺失配图。看个大概吧。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容