Android知识程序员Android开发

dex分包的最终方案

2017-08-23  本文已影响1110人  super_shanks
dex分包.png

这就是所谓的dex分包了。


需求的由来

实际上IDE默认为我们创建的dex分包方案已经足够我们在大部分的使用情景中不会出现任何问题了。但是如果出现了很特别的错误,你就会意识到可能系统的默认分包方案在某些情景下显得不那么好用了。

因为有同学跟我反映说在使用Tinker(微信开源热更新)的过程遇到的涉及分包的问题,我们一起来看一下:

java.lang.VerifyError: 
Rejecting class io.reactivex.internal.operators.observable.ObservableZip 
because it failed compile-time verification (declaration of 
'io.reactivex.internal.operators.observable.ObservableZip' 
appears in /data/user/0/com.mymoney/tinker/patch-125e62ff/dex/classes3.dex.jar)

这种问题如果你不使用热更新很难遇到,这是Square公司的Rxjava做的一件很操蛋的事情,这种VerifyError一般会产生在什么情况下呢?

各位可以跟着做如下的步骤试一下:
S1. 创建一个接口类ITestClass
S2. 创建一个类实现这个接口,如TestClass implements ITestClass
S3. 创建一个类,里面增加一个这样的方法:

void badMethod() {
    ITestClass[] arr = new TestClass[3];
    if (随便搞个条件) {
        arr = new ITestClass[3];
    }
    arr[0] = new TestClass();
}

然后把badMethod所在的类和TestClass分到同一个dex,写个demo加载这个dex,再尝试调用badMethod,就会出错了。

具体的解释如下,可能会让你恶心,眩晕,如果介意可直接跳过看结果

本质上这是因为art在校验aput指令的时候会去确认指向目标数组的寄存器的类型,如果因为分支语句导致有多种可能,则要求每个可能的类型都要能被resolve。由于补丁dex是分开进行dex2oat的,导致dex2oat在编译这个dex的时候找不到ITestClass,也就没法resolve,因此使badMethod所在的类被打上verifyerror标志。运行时一旦尝试加载有verifyerror标志的类,就会crash。
而直接安装完整的apk没问题,是因为apk里面所有符合classN命名的dex是一起做dex2oat的,这样就不会有某些类resolve不到的问题了。

讲简单一点就是说,如果你在类中出现的if else或者其他分支情况会影响变量的类型走向,就必须要将所有可能的类型都放在同一个dex文件中,否则就会出现VerifyError

那么再回到上面的error,Rxjava一定是做了如上所述的勾当,导致出现了这个问题,而且正如前面所说,直接安装完整的apk不会出现这个问题,但是一旦你是补丁安装,就会秒跪。

到此为止,自定义分包方案的需求就显得极为强烈了。
因为系统默认的分包方案很有可能会把你的Rxjava拆分到不同的dex文件中,而且你也不能确保之后不会再出现其他的存在VerifyError隐患的场景,当然如果你的补丁方案没有出现过此类问题话,可以command(ctrl) +w

从dexknife到dexknife-plus

前者还算比较大众,后者的话知道的人会更少一点,我们一一来看一下。

总结

最终,我们从DexKnife过渡到DexKnife-plus,找到最为合适的dex分包方案,解决了自定义dex分包之苦,从此再也不用担心由于处在不同dex包所带来的任何问题。只要你想,你可以将任何你所需要的文件放到主dex包中。

同时也带来依然值得优化的空间,比如指定文件放在指定dex包,dex包的优化压缩。大家可以fork DexKnife或者DexKnife-plus,同作者一道努力,创造出更加强大的dex分包方案。

上一篇 下一篇

猜你喜欢

热点阅读