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 优化

sequenceDiagram
    participant APK as APK
    participant FileSystem as 文件系统
    participant DexFile as DexFile
    participant odex as classesN.odex
    participant dexPathList as dexPathList.dexElements

    APK->>FileSystem: 解压 classes2.dex (Secondary dexes)
    FileSystem->>FileSystem: 压缩成 classes2.zip
    FileSystem->>DexFile: DexFile.loadDex 优化 classes2.zip
    DexFile->>odex: 生成 classes2.odex
    DexFile->>dexPathList: 添加 classesN.odex 到 dexPathList.dexElements
    dexPathList->>DexFile: 完成 dex 加载

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

  • 每个 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插件

这些后续再做研究吧。