🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
五、CLASS_ISPREVERIFIED 运行一下Demo,报以下错误。(AndroidStudio 2.0 可能不会报错,需要打包的时候才会出现错误,这是Instant run 导致的) ![](https://img.kancloud.cn/8b/5d/8b5deb7fbaeecf430ffc6b7c20a44a0b_1056x393.jpg) dexElements 的length = 2,看来我们的patch_dex 已经成功添加进去了。 但是从黄色框框和黄色框上面那一段log 提示中可以看出,MainActivity 引用了Cat,但是发现他们在不同的Dex 中。 看到这里可能就会问: 为什么之前那么多项目都采用分包方案,但是却不会出现这个错误呢? 我在这里总结了一个过程,想知道详细分析过程的请看QQ 空间开发团队的原文。 在apk 安装的时候,虚拟机会将dex 优化成odex 后才拿去执行。在这个过程中会对所有class 一个校验。 校验方式:假设A 该类在它的static 方法,private 方法,构造函数,override方法中直接引用到B 类。如果A 类和B 类在同一个dex 中,那么A 类就会被打上CLASS_ISPREVERIFIED 标记 。 被打上这个标记的类不能引用其他dex 中的类,否则就会报图中的错误在我们的Demo 中,MainActivity 和Cat 本身是在同一个dex 中的,所以MainActivity 被打上了CLASS_ISPREVERIFIED。而我们修复bug 的时候却引用了另外一个dex 的Cat.class,所以这里就报错了 。 而普通分包方案则不会出现这个错误,因为引用和被引用的两个类一开始就不在同一个dex 中,所以校验的时候并不会被打上CLASS_ISPREVERIFIED 。 补充一下第二条:A 类如果还引用了一个C 类,而C 类在其他dex 中,那么A类并不会被打上标记。换句话说,只要在static 方法,构造方法,private 方法,override 方法中直接引用了其他dex 中的类,那么这个类就不会被打上 CLASS_ISPREVERIFIED 标记。 5.1 解决方案 根据上面的第六条,我们只要让所有类都引用其他dex 中的某个类就可以了。 下面是QQ 控件给出的解决方案 ![](https://img.kancloud.cn/e6/36/e636c4c70294cd2352510e7cd804b8cd_664x320.jpg) 在所有类的构造函数中插入这行代码System.out.println(AntilazyLoad.class);这样当安装apk 的时候,classes.dex 内的类都会引用一个在不相同dex 中的AntilazyLoad 类,这样就防止了类被打上CLASS_ISPREVERIFIED 的标志了,只要没被打上这个标志的类都可以进行打补丁操作。 hack.dex 在应用启动的时候就要先加载出来,不然AntilazyLoad 类会被标记为不存在,即使后面再加载hack.dex,AntilazyLoad 类还是会提示不存在。该类只要一次找不到,那么就会永远被标上找不到的标记了。 我们一般在Application 中执行dex 的注入操作,所以在Application 的构造中不能加上`System.out.println(AntilazyLoad.class);`这行代码,因为此时hack.dex 还没有加载进来,AntilazyLoad 并不存在。 之所以选择构造函数是因为他不增加方法数,一个类即使没有显式的构造函数,也会有一个隐式的默认构造函数。 5.2 插入代码的难点 1.首先在源码中手动插入不太可行,hack.dex 此时并没有加载进来,AntilazyLoad.class 并不存在,编译不通过。 2.所以我们需要在源码编译成字节码之后,在字节码中进行插入操作。对字节码进行操作的框架有很多,但是比较常用的则是ASM 和javaassist 3.但AndroidStudio 是使用Gradle 构建项目,编译-打包都是自动化的,我们怎么操作呢。