众所周知,应用安装包的体积会十分影响用户的应用下载速度和安装速度 。据 googlePlay 平台对外发布相关的包大小对转化率影响的数据,我们可以看到随着包大小的增加,安装转化率总体呈下降的趋势 。
文章插图
因此对于我们的应用来说,为了提升我们用户下载的转化率(即下载安装激活用户与潜在用户的比例),我们对包体积必须给予一定的优化和管控 。
我们应用商店中提供给用户下载的安装包,是 Android 定义的 APK 格式,其实质则是一个包含应用所有所需资源的 zip 包,它包含了如下所示的几个组成部分:
文章插图
这其中最主要的组成部分便是 DEX 文件,它们都是由 JAVA/Kotlin 代码编译而成 。过去的两年中,抖音的 DEX 的个数从 8 个涨到了 21 个,DEX 的总大小从 26M 涨到了 48M,增长十分迅猛 。诚然,随着抖音的快速发展,业务复杂度的提高,代码量级一定是在增加的,但如何在业务无感的情况下,对代码进行通用优化,也是我们一个很重要的优化方向 。
在介绍具体优化手段之前,我们首先需要了解下针对 DEX 整体上的优化思路 。
DEX 通用优化思路在 AGP 的构建过程中,Java 或 Kotlin 源代码在经过编译之后会生成 Class 字节码文件,在这个阶段 AGP 提供了 Transform 来做字节码的处理,我们非常熟悉的 Proguard 就是在这个阶段工作的,之后 Class 文件经由 dexBuilder 生成一堆较小的 DEX 文件,再经由 mergeDex 合并成最终的 DEX 文件,然后打入 APK 中 。具体过程如下图所示:
文章插图
因此,我们针对 DEX 文件的优化时机可以从分别从三个阶段切入,分别是.kt 或.java 源文件、class 文件、DEX 文件:
- 在源文件进行处理也就是手动改造代码,这种方式对程序设计本身有侵入,并且有较强的局限性;
- 在 class 字节码阶段对开发者无感知,而且基本上能完成大多数的优化,但对于像跨 DEX 引用优化这样涉及 DEX 格式本身的优化无法完成;
- 在 DEX 文件阶段进行优化是最理想的,在这个阶段我们除了能对 DEX 字节码本身进行优化,也可对 DEX 文件格式进行操作 。
由于早期抖音 class 字节码修改工具建设比较成熟,我们很多包体积的优化都是通过修改 class 字节码完成的,随着优化的深入,后期也有很多优化是在 DEX 文件阶段处理的 。关于 DEX 阶段相关的优化我们后续会有相关文章介绍,这里主要介绍 Class 字节码阶段进行的相关优化,主要分为两大类:
- 单纯去除无用的代码指令,包括去除冗余赋值,无副作用代码删除等
- 除了能减少代码指令数量外,同时减少方法和字段的数量,从而有效减少 DEX 的数量 。我们知道 DEX 中引用方法数、引用字段数等不能超过 65535,超过之后就需要新开一个 DEX 文件,因此减少 DEX 中方法数、字段数可以减少 DEX 文件数量,像短方法内联、常量字段消除、R 常量内联就属于这类优化 。
去除冗余赋值在我们平时的代码开发中,我们可能会写出以下的代码:
class MyClass {private boolean aBoolean = false;private static boolean aBooleanStatic = false;private void boo() {if (!aBoolean) {System.out.println("in aBoolean false!");}if (!aBooleanStatic) {System.out.println("in aBooleanStatic false!");}}}
我们常常为了保证一个 Class 的成员变量的初始满足我们期望的值,手动对其进行一次赋值,如上述代码里的 aBoolean 和 aBooleanStatic 。这是一种逻辑上非常安全的做法,但这真是必须的吗?其实 Java 官方在虚拟机规范(https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-2.html#jvms-2.3)中定义了,Class对象在虚拟机中加载时,所有的静态字段(也就是静态成员变量,下面统称为Field)都会首先加载一个默认值
2.3. Primitive Types and Values
...
The integral types are:
byte, whose values are 8-bit signed two's-complement integers, and whose default value is zero
short... whose default value is zero
int... whose default value is zero
long... whose default value is zero
推荐阅读
- Android WebRTC 对 AudioRecord 的使用
- TikTok/国际版抖音/海外版抖音2万字干货教程,新手必看
- 作为Android开发,这个知识点一定要知道,官方也改了 2 次
- Android logcat日志封装
- 抖音防烧屏脚本 – Tasker 脚本分享,适用于 OLED 屏幕
- Android开发:使用Kotlin+协程+自定义注解+Retrofit的网络框架
- Android开发:当前项目以Module形式引用别的项目的步骤
- Android恶意木马伪装成游戏APP,通过华为AppGallery分发
- 2021年Android开发新技术动向,未来的路该怎么走?
- Uni-app离线打包Android APK详细教程