热修复选型:
目前国内主流的两种热修复策略有以下两种:以阿里系为主的底层method修复方案(Hotfix);基于修改dex结构的tx系类加载方案(Tinker)。-----阿里于17年推出的sophix方案其实是两个方案的集合体。
局限性和优劣性我借住以下图标来做个说明:
tinker是我目前学习使用的主流框架,主要原因在于其稳定性以及全面性,在实际开发中用于一些非紧急bug修复,以及作为紧急bug修复发版的辅助项。
先来聊一聊andfix(MethodHotFix)的使用感受吧,不稳定,不稳定,不稳定,重要的事情说三遍!!!!!在任何一个生产项目中,稳定性是衡量技术方案的最主要因素。
1:MethodHotFix基于规范的虚拟机底层,动态修改和扩展method,而国内各大厂商又会对底层做一定的定制修改,这样很容易导致失败。
2:app运行时,类结构已经固化在内存中,其动态属性很难扩展;
3: 底层替换方案是在已经加载的类中,直接替换原有方法,在原有类上进行修改。因而无法进行字段和方法的增减。因为这样会修改原有类的结构。举例:方法新增或者删除,会导致这个类或者整个Dex方法数修改,方法数的修改会导致方法索引的修改,这样在访问方法时,就无法访问正确的索引了。字段的增减会导致字段索引变更,如果一个类新增了某个字段,由新方法访问已经声明的未修改前的实例对象,就难以预知会发生什么。。
底层替换方案主要是依赖修改虚拟机方法实体的具体字段。
如修改Dalvik方法的 jni 函数指针,改类或者方法的访问权限等。
art虚拟机中,每一个Java方法在art中都对应着一个ArtMethod,ArtMethod记录了这个Java方法的所有信息,包括所属类、访问权限、代码执行地址等等。而andfix根据标准的ArtMethod进行修改,然而各大厂商又可能修改了底层的ArtMethod,这样通用的替换机制就会出现问题。
数组优化,不理解
类加载方案:代表作Tinker,冷启动,需要重启生效
类加载方案,是app在重启后,让classLoader去加载新类。在app运行中,需要修改的类已经加载过了,android是无法将一个类进行卸载的。不重启的话,原有的类还在虚拟机中,无法加载新类。
QQ空间方案需要侵入打包过程,为了支持hack会添加一些无用信息,不够优雅。QFix修复方案需要获取底层虚拟机函数,不够稳定可靠,且无法新增public函数。
Tinker是完整的全量替换dex方案,通过DexDiff算法的实现,我们既解决了Dalvik平台的性能损耗问题,又解决了Art平台补丁包过大的问题。但这套方案的缺点在于占Rom体积比较大,微信考虑到移动设备的存储空间提升比较快,增加几十M的Rom空间这个代价可以接受。
sophix,阿里最新的热修复方案,在类加载实现中,也是采用dex全量替换的过程,但是颗粒主要是在类维度上。