天涯论坛

 找回密码
 立即注册
搜索
查看: 91|回复: 0

百度APP Android包体积优化实践(一)总览

[复制链接]

3074

主题

148

回帖

9911万

积分

论坛元老

Rank: 8Rank: 8

积分
99118898
发表于 2024-7-9 17:48:24 | 显示全部楼层 |阅读模式

GEEK TALK

01

前言

此前百度APP已然具备基本的包体积优化机制、约束和认识,但做为巨舰型APP,业务的高速迭代仍然不可避免地造成为了包体积爆炸式增长。包体积或直接或间接地影响着下载转化率、安装时间、运行内存、磁盘空间等要紧指标,因此投入精力扫除积坏处、发掘更深层次的体积优化项是非常必要的。

按照谷歌商店的内部数据,APK体积每减少10M,平均可增多~1.5%的下载转化率,如下图所示:

图1 谷歌商店应用转化率增多幅度 / 10M [1]

Android包体积优化手段有非常多例如业务裁剪、插件化、混合研发、资源后下发等。本系列文案重点针对的是业务关、集成在APK中的内容的体积优化,如Dex优化、资源优化、so优化等,咱们叫作之为基本机制优化。

包体积基本机制优化实践将会以系列文案的方式呈现,重点包含以下部分:心路历程、Dex行号优化完整方法、资源优化实践与探索、Dex优化实践与探索、so优化探索、其他优化经验与总结。

本文讲述的是百度APP包体积基本机制优化心路历程,包含连续指点功效的基本思想、优化对象分析、对现有优化工具的学习、以及最后产出的体积优化项。

GEEK TALK

02

基本思想

2.1 分而治之

们的优化对象不只是APK这个最后产物,包含APK中的内容,这些内容的体积优化思路与手段不尽相同。

2.2 可连续优化

好的优化机制不止生效于当下,生效于将来。举例来讲,从源码仓库删除当前的Dead Code属于一次性存量优化操作,而编译器的DCE机制(Dead Code Elimination)连续生效于将来产生的Dead Code。从长线思虑咱们应优先创立后者,而后倒推前者的执行。

2.3 站在前人的肩膀上

包体积优化并不是一个鲜嫩专题,Android官方和研发者们都在连续致力于优化体积。重复造轮子是不被提倡的,但针对区别的应用场景,尤其是巨舰型APP,体积优化应该有定制化的方法

2.4 知道代价,有所取舍

按照热力学第必定律,收益不会凭空产生,必定伴同着代价,例如人力的投入、编译时间的增多、适配难度的增多等。知道代价后,咱们才可决定某优化项是不是要做、何时做、怎样做。

2.5 约束与认识

除了自动化的优化机制,还必须配套有自动化的体积增长约束,同期从源头提高研发者的体积优化认识,多管齐下才可达到最优效果。

GEEK TALK

03

APK结构分析

接下来咱们会简单分析下APK构成部分,以及APK做为ZIP,其标准结构是什么样的。

3.1 APK内容分析

图2 APK 结构

classes.dex

APK 中可能包括一个或多个 classes.dex 文件,应用程序内的 Java/Kotlin 源码最后会以 dalvik 字节码的方式存在于 classes.dex 文件中。

resources.arsc

该文件是包括配置信息的资源查找表,起着链接代码与资源的功效。Dex 文件中的 R.class 仅包括资源 id,AssetManager 会利用 id 到 arsc 表中查找与当前设备信息最匹配的资源文件路径(或资源内容)。

res/

包括源码工程中 res 目录下除了 values 外的资源文件,这些文件路径同期表现在 resources.arsc 中。

lib/

native libraries。即源码工程 jni 目录下的 so 文件,二级目录必要为 NDK支持的 ABI。

assets/

与 res/ 资源目录区别,assets/ 下的资源文件不会在 resources.arsc 中生成查找条目,且 assets/ 下的资源目录可完全自定义,业务代码获取 assets 资源和 res 资源的方式完全区别

META-INF/

应用签名信息。该目录在应用签名后生成,包括以下三个文件:

MANIFEST.MF:摘要文件,包括APK内所有文件的路径及其 SHA1/SHA256 值。

CERT.SF:对摘要的签名文件,包括APK内所有文件的路径,及其在 MANIFEST.MF 中对应信息的 SHA1/SHA256 值。

CERT.RSA:保留公钥、加密算法及其私钥加密后的内容。

AndroidManifest.xml

应用名单文件,用于描述应用基本信息,重点包含应用包名、应用id、应用组件、所需权限、设备兼容性等。

3.2 ZIP结构分析

图3 ZIP 标准结构示意图

压缩源文件信息

Local file header:描述源文件信息。

File data:源文件数据。

Data descriptor:校验码及压缩前后体积

中心目录区

Central directory

记录 ZIP 目录结构。每一条 file header 对应一个源文件,描述文件关联信息。

中心目录结束标识

End of central directory record

标识 ZIP 包结束,包括 ZIP 包及中心目录的简要信息。

GEEK TALK

04

现有优化工具介绍

针对发展初期的应用,体积优化的优先级较低,直接运用以下体积优化工具是性价比最高的选取。百度APP 一样对比借鉴了以下工具,从中衍生出了全新的、定制化的优化需求。

4.1 roGuard

在 AGP3.3 之前,ProGuard 做为官方体积优化工具,负责在编译完成之后对class 文件进行缩减混淆等操作,其优化结果交给 Dx/D8 转化为 Dex 产物。图4 Proguard 处理对象及功效示意图 [9]ProGuard 的优化操作重点包含缩减:安全移除用类、办法、字段和属性。混淆:缩短类与成员的名叫作优化:指令级别的优化,合并重复指令、清理用指令、提高指令执行效率。

4.2 R8

AGP 3.3之后官方起始举荐运用 R8,R8 与 ProGuard 不只是简单的替代关系,它还将脱糖、D8 整合到了一块极重提高了构建效率。图5 R8 处理对象及功效示意图 [9]R8 基本兼容此前的 ProGuard 规则,但仍存在些许差异(applymapping、行号处理、Kotlin元数据处理、用判定等)。R8 再也不高优思虑兼容性问题后,两者会派生出越来越多的区别点,意见定时关注,博采众长。丨Jack & Jill小插曲:官方在2015年推行过一段时间的Jack & Jill工具,它乃至把javac包括了进来,算是真正实现了端到端的编译。但Jack的性能与生态相比javac实在差距太大,官方出于成本思虑最后还是弃坑了。

4.3 AndResGuard

AndResGuard 是微X推出资源优化工具。它的基本思想类似于 ProGuard 中的混淆,体积优化是它的附加收益,同期供给了压缩、加密等选项。

4.4 ByteX

ByteX 是字节开源的一套Java字节码插桩工具日前重点包含优化与检测工作,其中有些子项最后会带来体积收益。包含R类内联、移除debug信息、access 办法内联等。

4.5 Booster

Booster 是滴滴开源的一套质量优化框架,其中包含体积优化专项,例如资源文件压缩、资源产物.ap_ 压缩、去冗余资源、R类内联、DataBinding BR内联等。

4.6 AGP

Android Gradle Plugin(AGP)包括了多个体积优化任务,供给了许多优化配置项,大部分任务已然做为APK打包的标配。

通常来讲,咱们的优化任务会依赖于这些任务的执行。倘若定制的优化法兼容现存任务,则必须关闭或hook这些任务。接下来将根据编译次序简单介绍几个优化任务与配置:

OptimizeResources

AGP4.2+ 新增的资源优化任务,日前只实现了资源文件路径的缩短,默认开启,可经过 android.enableResourceOptimizations 关闭。

StripSymbols

NDK 会利用 llvm-strip 移除掉 native libraries 中的unneeded symbols,这部分优化工作能够放在so编译时期完成。

MinifyWithR8/ProGuard

利用 R8 或 ProGuard 实现代码优化,此处就再也不赘述了。

ShrinkResources

由 ShrinkResources 开关掌控,启用前提是必要开启 minifyEnable。其功效是将未被引用的资源文件替换为一个体积很小的格式文件
(仍存在占位体积,同期保存了该资源条目,因此 resources.arsc 体积并不会减少),可经过 res/raw/keep.xml 文件配置 shrinkMode 和白名单。

PackageOptions

打包时选项,包含过滤 exclude、相同文件仅打包 pickFirst、所有打包 merge、so优化豁免 doNotStrip。

Splits

分包/过滤策略,配置项包含 ABI、资源配置(语言、分辨率等)。

GEEK TALK

05

百度APP优化项项概览

5.1 Dex优化

百度APP 实现 Dex 的体积优化项能够分为两类:源码编译时期的优化;APK 打包时期对 Dex 文件的优化。两者的区别重点是优化对象区别因此基于区别的优化工具实现,前者基于Java字节码工具实现(如 ASM),后者基于 Dex 字节码工具实现(如 Titan-Dex [10])丨Titan-DexTitan-Dex 是百度开源的面向Android Dalvik(ART)字节码(bytecode)格式的操作框架,能够在二进制格式下实现修改已有的类,动态生成新的类。百度Titan-hotfix工具即基于此框架实现。R类优化       工程组件越多,R类所占体积越大,未关闭资源依赖传递的状况下则更严重。咱们在编译期将代码中调用 R.type.name 的地区所有替换成为了对应的id常量,最后 R.class 会做为用类被 R8/ProGuard 清理掉。行号优化Dex 中的 debug 区域占5~10%的体积,但其最大的功效是分析崩溃堆栈时定位。该区域能够经过去除 ProGuard 规则-keepattributes SourceFile,LineNumberTable 完全移除。咱们选取在指令级别完成 debug infos 的映射与复用,同期联动百度性能平台(日前仅供机构内部运用,功能可类比腾讯 bugly)完成崩溃堆栈的还原,既优化了体积,又不会影响堆栈的分析。注解优化       Dex中注解分为三种类型:Build、Runtime、System。Build 和 Runtime对应 ProGuard 规则 -keepattributes *Annotation*,可优化的 System 注解按照详细类型分别对应-keepattributes InnerClasses, Signature, EnclosingMethod。跟行号同样能够经过去除这些规则完成一刀切的优化。但因为咱们接入的三方组件自带这些 ProGuard 规则,且部归类的 System 注解有保存必须咱们选取后置地处理 Dex 文件,基于 Dex 字节码工具完成目的注解的移除。

5.2 资源优化

资源优化的对象分为两类,一是资源查找表 resources.arsc,部分优化操作会触及到 res/ 及 R文件的修改,但本质都是从 resources.arsc 出发的;二是原始资源文件,包含 res/和 assets/。介绍优化项前,咱们先看一张网上最经典的 resources.arsc 结构图(源自CSDN社区)图6 resources.arsc 结构图资源同名化实质应用中,咱们默认经过资源 id 查询资源内容,对资源名的运用频率非常低,仅限于经过资源名反查资源 id 以及 经过资源 id 获取资源名两种状况因此资源项名叫作字符串池所占据的空间即是咱们的优化对象。极限优化结果是,这个池子里仅存放一个字符串,所有 ResTable_entry 的资源项名叫作 index均指向这个池子里仅有的字符串,即所有资源的名字都变得同样了。实质场景中,咱们会有豁免和降级为混淆的需求,例如经过资源名反向查找资源id等状况资源文件路径优化与 AndResGuard 中的资源路径混淆效果类似,都是尽可能缩短资源文件的路径长度,从而减少 ResTable_entry 的 value 体积咱们将路径 Hash 值转换到碰撞最少的位数,做为最后的混淆结果,其优点在于混淆结果基本上是固定的,需 applymapping。除此之外,咱们还较为激进地去掉了大部分文件的后缀名。资源配置优化从 arsc 中的资源 id 包括了偏移量信息,系统经过偏移量在 arsc 中定位资源。因此图7中的空白区域必要保存一个4字节的占位,以满足偏移量查找方式。咱们正在对此部分做优化,宗旨是经过优化不必要的 configuraion,达到减少对齐占位的目的。图7 resources.arsc 空白占位示意图照片压缩       因为 webp 格式受限于 minsdkversion18,咱们日前还是针对 png 照片做压缩优化,运用工具包含 TinyPng 和 ImageOptim。除了出图周期压缩外,会有后置流水线做压缩检测用资源清理如4.5中说到的,ShrinkResources 并不会真正移除未被引用的资源文件。不外咱们能够拿到被 shrink 的 resources 列表,而后再利用资源优化工具做真正的删除。丨New ShrinkResource

2022.1发布的 AGPv7.1.0 更新了资源缩减功能,添加了实验性选项 android.experimental.enableNewResourceShrinker.preciseShrinking,该选项设置为true后 ShrinkResources 会完全移除未运用的文件资源及 value 资源,但 arsc 中仍会存在这些资源的填充占位。

arsc 压缩resources.arsc 的压缩体积收益很高,但对其进行压缩会影响起步速度和内存指标。详细原由是:系统在加载 arsc 文件时,若 arsc 文件未压缩,可运用 mmap 进行内存映射;若 arsc 文件被压缩了,则必须将其解压缩后读取到RAM 缓冲区,会增多内存运用会拖慢起步速度。在业界大都压缩 arsc 的状况下,百度APP 出于综合考量始终未对 arsc 文件进行压缩。独有偶,官方出于一样思虑,从 Android11 起始强制需求resources.arsc 不可压缩且保持4位对齐,否则会直接安装失败。图8 Android11强调 resources.arsc 压缩对齐问题

5.3 ZIP优化

压缩       日前咱们运用的压缩算法有 7z 和 zopfli[11],后者压缩率和压缩耗时都有显著增多,稳定性还在验证中。采用新的压缩算法时需尤其重视两点,一是不要压缩 resources.arsc;二是重视压缩、 对齐、签名操作的次序文件路径优化如章节3.2 ZIP结构分析所示,APK 中有三处体积与文件路径长度关联:META-INF/、压缩源文件数据区的 local file header、中心目录区的 file header,资源文件路径优化效果一样表现这儿。同理掌控 assets/ 下的文件路径可带来体积收益。

5.4 其他

夜间模式优化日前百度APP的夜间资源是一个 APK 包,此前实现方式是与主包中的资源名保持一致,经过反射的办法查找对应 id。现改为 id 一致,这般既避免了反射查找的耗时,章节 5.2中的资源优化能够应用到资源 APK,进一步减小体积。混淆规则ProGuard/R8 供给了多种多样的规则用以豁免代码优化操作,倘若运用欠妥可能会导致体积的白白浪费。将来咱们计划制定一套仔细的 ProGuard 规则运用规范,并对每一个组件的 ProGuard 规则都进行校验,例如不准许显现本组件包名范围外的 keep 规则、不准许显现包级别 keep 等。体积流水线重点包含仓库体积约束流水线,二进制组件体积检测流水线,以及 APK 构成体积分析流水线,分周期进行约束与分析。日前百度APP 建设了 APK 体积监控流水线,每当主线有代码合入、触发编译打包后,会即时对编译产物 APK 做体积分析,并与上一次编译产物进行比对,能够马上发掘反常的体积增长。

GEEK TALK

06

总结

第五章介绍的优化项自21年8月至22年2月分批次上线,时期业务依旧在高速迭代,虽然有体积监控流水线功效,包体积仍会不可避免地增多因为优化机制非常底层,需进行充分的线下测试与线上小流量灰度,验证稳定性后才可正式上线。上线/灰度前后百度APP 包体积体积例如下:优化项优化前体积优化后体积DiffDex 行号优化 & 混淆规则收敛 (上线)123.58MB119.37MB4.21MB资源名/路径优化 & 7z 压缩 & 夜间模式优化(上线)122.54MB116.36MB6.18MB照片压缩 & 热修插桩优化 (上线)117.07MB116.00MB1.07MBDex 注解优化 (灰度)117.16MB115.95MB1.21MB启用R8 (灰度)119.06MB116.62MB2.44MBzopfli 压缩 & 资源缩减 & 资源配置优化(灰度)119.57MB116.65MB2.92MB本文重点介绍了百度APP 包体积优化的基本思路,解构了优化对象,介绍了现有优化工具,最后简单介绍了百度APP 详细实践的优化项及收益。后续咱们会针对每一个优化类型仔细介绍其原理与实现,同期逐步开源通用的体积优化工具,敬请期待。

 END

参考资料:

[1] 包体积与安装转化率 https://medium.com/googleplaydev/shrinking-apks-growing-installs-5d3fcba23ce2[2] ZIP格式 https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.2.0.txt[3] roGuard  https://www.guardsquare.com/proguard[4] R8 https://r8.googlesource.com/r8[5] roGuard与R8对比 https://www.guardsquare.com/blog/proguard-and-r8[6] AndResGuard https://github.com/shwenzhang/AndResGuard[7] ByteX https://github.com/bytedance/ByteX[8] Booster https://github.com/didi/booster[9] AGP https://developer.android.com/studio/releases/gradle-plugin[10] Titan-Dex https://github.com/baidu/titan-dex[11] zopfli https://en.wikipedia.org/wiki/Zopfli举荐阅读:

百度APP iOS端内存优化实践-大块内存监控方法

百家号基于AE的视频渲染技术探索

百度工程师教你玩转设计模式(观察者模式)

Linux透明大页机制在云上大规模集群实践介绍

有效!Swagger-Yapi的奥密

百度直播iOS SDK平台化输出改造

一键三连,好运连连,bug不见




上一篇:百度APP Android包体积优化实践(二)Dex行号优化
下一篇:12个谷歌SEO优化技巧:提高网站排名与流量
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

站点统计|Archiver|手机版|小黑屋|天涯论坛 ( 非经营性网站 )|网站地图

GMT+8, 2024-11-23 01:28 , Processed in 0.113965 second(s), 21 queries .

Powered by Discuz! X3.4

Copyright © 2001-2023, Tencent Cloud.