支付宝 App 构建优化解析:压缩 Android 包大小,提升运行效率和质量

2024-11-15
来源:网络整理

文末互动有奖品。欢迎参与二维码问卷调查。

文末留言提问

前言

本章我们将围绕“支付宝App构建优化分析”展开新系列,从“代码管理”、“证书管理”、“版本管理”、“构建和构建”等维度来分解客户端的具体实施方案。包装”等讨论,带领大家进一步了解支付宝在App构建模块下的持续优化。

本节将主要记录如何通过压缩支付宝包的大小来提高运行效率和质量。

背景

封装尺寸的重要性不用多说。包大小直接影响用户的下载量和留存率。一些制造商的预安装要求必须小于某个值。但随着业务的迭代发展,应用会越来越大,安装包也会不断扩大,所以包大小缩减是一个长期的管理过程。

计划

支付宝也一直在努力优化包裹尺寸,我们推出了很多解决方案。

例如:代码混淆、图像从png到webp的转换、7zip压缩方案的引入等。

该方案与上述传统方案不同。通过直接删除dex中无用信息,达到瞬间将支付宝包大小缩小2.1M的目的。不影响整个操作逻辑和性能,甚至可以减少一点操作。记忆。

解决方案介绍

dex文件的结构其实很清晰,分为几个大块,区、索引区、数据区、映射区。本优化方案对数据区中的区域进行了优化和删除。

函数参数变量和所有局部变量

所有指令集行号与源文件行号的对应关系

有什么用:

第一点其实是非常明显的。既然调用了,那么使用IDE的时候就必须使用它。我们通常在使用IDE进行断点和单步调试时会用到这个区域。

第二个作用是在上报或者主动获取调用栈的时候使用它,因为虚拟机真正执行的时候,是执行的指令集,通过上报栈上报的对应的源文件行号来获取对应的使用下面的截图可以更直观地理解行号:

支付宝安卓源码_支付宝2088源代码_支付宝app源码

.png |左|

上图是一个比较常见的资料。红框中的行号是通过搜索this得到的。

选项1

核心思想也比较简单,就是让线号搜索离线,这样可以提前提取出原本存储在App中的线号对应关系,并存储在服务器上。上报时,可以通过预先提取的行号表来解码行号。解决上报信息无行号、无法定位的问题。

虽然想法很简单,但实现起来还是有点复杂,上线的推广也相当曲折。该计划已多次调整。总体规划可以用下图来概括:

|左边

如上图所示,核心点有四个:

修改,使用删除( -keep),在删除行号表之前转储一个临时dex。

修改,将临时dex中的行号表关系转储到文件中(指令集行号与源文件行号的映射关系),并保存到服务器端。

hook app将当前指令集行号报告给反解密平台。

反解密平台通过上报指令集行号并提前准备文件来解码出正确的行号。

上述计划花了两周多的时间来创建整个演示。其他的修改点并不难。困难仍然在于报告指令集行号。

我们知道一切最终都会有一个对象,它存储了整个堆栈信息。经过反复阅读源码和尝试,发现我想要的指令集行号居然就在这个对象中。可以用下面这张简单的图来说明:

在打印堆栈信息之前,都会调用art虚拟机提供的一个jni方法,并返回一个名为 in the 的内部对象。这个对象中保存的是整个方法的调用堆栈,当然也包括指令集行号。 ,后面获取实际的堆栈信息时,会调用art的一个jni方法,这个方法就会被抛出。底层会通过该对象中的指令集行号解码出正式的源文件行号。

好吧,其实很简单。反射获取this中的对象,获取指令集行号,然后上报。

这里需要注意的一点是非常恶心的。每个虚拟机的实现都是不同的。首先内部对象有的名字叫,有的叫,然后内部对象有很多种类型。有些是 int 数组,有些是 long。数组,有些是对象数组,但是它们都有这个指令集行号。对于不同的虚拟机版本,需要使用不同的方法来解析这个对象。必须兼容4.x、5.x、6.x、7.x 4种类型的虚拟机,7.x虚拟机将会统一。

支付宝安卓源码_支付宝2088源代码_支付宝app源码

选项2

上面的方案其实已经相当完美了。不存在兼容性问题。直接删除,在Java层直接获取指令集行号。不需要各种挂钩。如果只需要处理报表,方案一就足够了,但是支付宝中有很多场景这还不够。

例如:

上述情况都涉及到堆栈信息。第一种方案中,通过反射调用的内部对象根本无法处理,需要另一种方法。

最初的想法是尝试hook art虚拟机,每天看源码,看看哪些点可以hook。最后我放弃了。一是因为担心兼容性问题,二是hook点太多,让我慌了。

最后我改变了主意,尝试直接修改dex文件,留下一小块,这样系统查找行号时,指令集行号和源文件行号保持一致。这样就不需要做任何事情,监控上报的任何行号都直接成为指令集行号,只需修改dex文件即可。可以用下面的示意图来表示:

|左边

如上图:本来每个方法都有一个,每个方法都有指令集行号和源文件行号的映射关系。我做的修改其实很简单,就是把多余的全部删掉,只留下一个,所有的方法都指向同一个,而且这里面的指令集行号和源文件行号一致,所以没有无论用什么方法查看行号,得到的都是指令集行号。

我也遇到过很多陷阱。事实上,仅仅留下一个是不够的。为了兼容所有虚拟机的搜索方式,需要进行分区,并且表不能太大。如果遇到陷阱,你会经常进行优化。遍历这个导致AOT编译比较慢,最终通过分区解决。

该解决方案更加彻底,不需要任何更改或挂钩。不过,如果你只需要处理行号问题,那么仍然推荐第一个选项。这个选项的改动有点大。前期我每天研究dex的文件结构,挖掘每一个细节,只有比较有信心的时候才敢改。

概括

目前,该解决方案已在支付宝正式上线。经过几轮外部验证,还是比较稳定的。支付宝包整体大小减少了约2.1M,真实dex大小减少了约3.5M。

通过本节的内容,我们初步了解了支付宝如何在客户端利用包大小压缩来提高App运行效率和质量。关于端包大小压缩的设计思路和具体实践,我们也期待您的反馈。欢迎大家一起讨论交流。

即日起,填写并提交开发者调查问卷,就有机会获得限量版蚂蚁U型枕。

帮助团队进一步了解您的需求和痛点,以便我们更好地开发和改进产品。我们期待您的反馈。

本次问卷采集截止时间为晚上11.30 18:00,抽奖过程由【 Bus】官方团队全程监督。

分享