享学课堂特邀作者:周周
转载请声明出处!
前言
上文Android热修复主流方案盘点 中,提到了4种比较出名的热修复方案,
- 腾讯Qzone超级补丁的
multidex
方案, - 腾讯Tinker的
dexdiff
方案, - 阿里
andFix
的纯native
方法指针重定向方案(已废弃,因为有了新的替代方案sophix
), - 美团的
robust
的instantRun
方案。
然而,在android多版本的兼容上,这些热修复方案多多少少存在一些问题。
本文思路来源为两篇官方技术博文:
安卓App热补丁动态修复技术介绍
Android N混合编译与对热补丁影响解析
可惜大佬发文一般人看不懂,所以我重新解读一下,更通俗易懂地展示这两个坑的解决方案.
正文大纲
CLASS_ISPREVERIFIED
兼容问题Android N
混合编译兼容问题
正文
CLASS_ISPREVERIFIED 兼容问题
Demo地址:https://github.com/18598925736/HotUpdateDemo/tree/4.4_crash_solution
问题描述
一句话描述问题:
在apk安装的时候,Dalvik虚拟机如果发现 一个类A它所引用的其他类,和它自己都处于同一个dex文件内部,那么类A就会被打上一个
CLASS_ISPREVERIFIED
标记,从而提高性能。那么按照这个思路,如果类A引用了一个有bug的类Util,然后我们用multidex热修复方案给他推了一个patch.dex,然后重启修复,这个类已经被打上了标记,但是重启app之后,它所引用的类Util 此时和它又不处于一个dex内(新的Util类在patch.dex内)。此时,起了一个冲突,既打上了标记,又发现不处于一个dex内的引用类,程序就会报错。
CLASS_ISPREVERIFIED 分4个单词 class , is , pre verified ,
类
是否被预先校验
。
此问题只会出现在Dalvik虚拟机之下(4.4 sdk19 以下默认使用dalvik,5.0 sdk 21 以后便默认使用art虚拟机),art不会有类似问题。所以可以认为此问题只出现在**5.0以下(不含5.0)**的机器上.
问题演示
我使用的是上一篇文章的 Android Muitldex热更新修复方案原理的demo
下载之后,直接运行在SDK 19 android4.4的模拟器上。
这是一个已经加入了补丁包fix.dex的demo工程。
当你直接运行,会发现程序崩溃,报错如下:
大概意思就是 有一个类的引用预先校验了,但是没有找到预想中的实现。这就是由于 被打上了
CLASS_ISPREVERIFIED
标记之后又执行了补丁修复,造成冲突。
解决方案
既然问题的根源在于 引用Util的A类被打上了
CLASS_ISPREVIRIFIED
标记,那么有没有办法让这些类不被打上标记呢?
思考:
问:如何防止我们源代码中所有的类被打上
CLASS_ISPPREVERIFIED
标记?
答:
理论上,一个android工程中所有的java类(除了Application之外)都有可能需要热修复。如果让这些类都去引用一个另一个dex文件之下的class,就能防止在dex解析的时候被打CLASS_ISPPREVERIFIED
标记。
但是这样有一个弊端,就是CLASS_ISPPREVERIFIED
带来的性能提