Szhangbiao's blog

记录一些让自己可以回忆的东西

0%

App启动优化之BoostMultiDex

在启动优化方面除了常规的设置主题图片防止出现白屏或黑屏,Application 的 onCreate 方法里精简业务逻辑和三方 SDK 异步或者延迟初始化,精简首屏页面的复杂度等之外,现在有了一个新选择,就是字节出品的BootMultiDex框架。

背景

我在开发阶段其实一直在关注 App 的启动时间,Android5.0 及以上在混淆后表现良好,几乎看不到黑屏,但是在Android4.4上,在做了上述常规优化后,在 App 未混淆前,启动时的黑屏能达到 4-5s,混淆后依然有 1-2s 的黑屏时间,而且默认主题图片停留的也较长,这时就不得不采用一些手段来进行优化,在做了一番调研后,发现字节出品的 BoostMultiDex 很契合我们现在的需求,它是一款用于 Android 低版本设备(4.X 及以下,SDK < 21)快速加载多 DEX 的解决方案。

MultiDex 过程

MultiDex会在主线程中对 APK 内的原始 DEX 文件做 ODEX 优化

APK文件系统DexFileclassesN.odexdexPathList.dexElements解压 classes2.dex (Secondary dexes)压缩成 classes2.zipDexFile.loadDex 优化 classes2.zip生成 classes2.odex添加 classesN.odex 到 dexPathList.dexElements完成 dex 加载APK文件系统DexFileclassesN.odexdexPathList.dexElements

这里存在性能瓶颈有两个地方:

  • 每个 Secondary dex 会创建对应的 zip 文件
  • 通过 DexFile.loadDex 对 zip 文件做 dexopt,会做一次解压,并且 dexopt 非常耗时

BoostMultidex 核心思路就是避免启动时候 ODEX, 先直接加载原始 DEX 完成启动,再在后台服务进程完成 ODEX 优化,下次冷启动就可以使用 ODEX 的代码

BoostMultiDex 要点

通过官方的介绍,再加上阅读源码可以知道,BoostMultiDex技术要点如下:

  • 利用系统隐藏函数,直接加载原始 DEX 字节码,避免 ODEX 耗时
  • 多级加载,在 DEX 字节码、DEX 文件、ODEX 文件中选取最合适的产物启动 APP
  • 单独进程做 OPT,并实现合理的中断及恢复机制

BoostMultiDex 使用

使用的话也特别简单,跟官方的MultiDex差不多

首先在引入依赖

1
2
3
4
5
dependencies {
...
// For specific version number, please refer to app demo
implementation 'com.bytedance.boost_multidex:boost_multidex:1.0.1
}

其次在 Application.attachBaseContext 的最前面进行初始化即可:

1
2
3
4
5
6
7
8
9
10
11
public class AppApplication extends Application {

@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
BoostMultiDex.install(base);
...
}
...
}

因为是大厂出品,在使用上其实没有过多的担忧,为防止意外发生,为此我还准备了一份设备白名单,如果 App 在这个设备上启动出错是因为引入BoostMultiDex造成的,我会把这些设备的型号放到白名单里,让其使用官方的MultidDex方案。最后通过几轮测试都没有发现问题,也就放心的在生产环境使用了。

总结

总体使用下来,优化效果还是蛮显著,Android 4.4启动时几乎看不到黑屏了,默认主题图片也没有等待过长的时间。
继续探索 App 启动优化的话还有其他的方案,比如:

  • Facebook 出品的ReDex
  • Booster 库下 booster-r-inline插件

这些后续再做研究吧。