Android热修复

来源:互联网 发布:知乎 户外保暖帽子 编辑:程序博客网 时间:2024/04/30 13:34

1.什么是热修复
热修复,又称热补丁,一般是用事先定义好的接口,从网络下载代码并更新客户端代码,从而在用户无感知、也无需重装App的情况下,实现动态修复或动态更新。

2.为什么需要热修复
对开发人员:
快速作用,方便测试和反馈,节省应用发布时间,缩短开发周期,降低开发成本;
方便数据统计和ABTest,有利于更好地改进App。
对用户:
无感知,无需重新下载安装,用户体验更好。

3.怎样实现热修复
目前较为成熟的方案主要有两种:

1).Classloader替换类方案(以NUWA或RocooFix为例)

原理:如果多个dex里有相同的class,那么虚拟机会优先使用最先加载的dex中的class。所以将有问题的类打包到一个新dex(pathc.dex)中,然后下发给App,App 启动时将该patch.dex插入到其他dex前面优先加载,就达到了替换有问题class的目的。

难点一:改变dex加载顺序。我们可以通过DexClassLoader对象将补丁dex对象加载进来,再通过反射将补丁dex插入到dexElements最前面即可。如下:
这里写图片描述

首先分别获取到宿主应用和补丁的dex中的PathList.dexElements,并把两个dexElements数组做拼接,将补丁数组放在前面,最后将拼接后的数组再赋值回Classloader。

难点二:防止class被打上class_ispreverified标记。

首先解释这个标记。我们知道当一个apk在安装的时候,apk中的classes.dex会被虚拟机(dexopt)优化成odex文件,然后才会拿去执行。dex转化成odex时会执行dvmVerifyClass进行类的校验,如果一个类和它直接引用到的类都在一个dex里,则它会被打上class_ispreverified标记,表示不需要去其他dex中加载类了。因此一旦我们要修复的类出现在被打上该标记的类中,修复就会失效。

解决方法就是,编译时通过脚本的字节码操作,在所有类的构造方法中插入一段代码,让所有的类都引用一个单独dex的一个类,这样所有的类都不会标记class_ispreverified了。不过这也就失去了class_ispreverified的意义,会有性能上的影响。

总结:该方案可以在class层级上做修复,成功率较高,兼容性也较好。但是由于强制使每个类都引用了其它dex的类,会造成一定的性能损失。

2).Native hook方案(以AndFix为例)

原理:

这里写图片描述

该方案首先通过对比修改前后的apk文件得出两个dex文件中同时存在的方法,如果修改过,则利用自定义的Annotation(MethodReplace)标注,最后将这些修改过的方法打包成补丁文件。然后,在将补丁下发到App后,就可以跟据补丁文件中的注解来找到所有需要替换的方法,然后调用native方法去实现方法的替换。如下图:

这里写图片描述

替换方法的关键在于native层怎么影响内存里的java代码。我们知道,在java代码里将一个方法声明为native方法时,对此函数的调用就会到native层找。本方案原理就是将一个不是native的方法修改成native方法,然后在native层进行替换,通过dvmCallMethod_fnPtr函数指针来调用libdvm.so中的dvmCallMethod()来加载替换后的新方法,达到替换方法的目的。

替换方法的native实现如下:

这里写图片描述

总结:该方案是在method层级上做修复,不需要App重启即可生效。但它也有其局限性,如无法添加新类、无法添加或修改成员变量等。

4.两种实现的比较
以下是两个方案的区别列表:
这里写图片描述

另外,NUWA和AndFix这两种方案都有较好的兼容性,同时支持art和dalvik模式,支持Android 6.0。

5.结论
NUWA和AndFix是当前相对比较成熟的热修复方案。NUWA的修复成功率较高,但是不能实时生效,对性能也有较大影响;而AndFix可以实时生效,但修复范围有限制。他们各有优劣,需要根据具体的需求来选择。

转载自:

http://www.cnblogs.com/noodleutopia/p/5784831.html

0 0
原创粉丝点击