热修复
Last updated
Was this helpful?
Last updated
Was this helpful?
参考
插件化和热修复不是同一个概念,虽然站在技术实现的角度来说,他们都是从系统加载器的角度出发,无论是采用hook方式,亦或是代理方式或者是其他底层实现,都是通过“欺骗”Android 系统的方式来让宿主正常的加载和运行插件(补丁)中的内容;但是二者的出发点是不同的。插件化顾名思义,更多是想把需要实现的模块或功能当做一个独立的提取出来,减少宿主的规模,当需要使用到相应的功能时再去加载相应的模块。热修复则往往是从修复bug的角度出发,强调的是在不需要二次安装应用的前提下修复已知的bug。
Android中类的加载也是通过ClassLoader来完成,具体来说就是PathClassLoader 和 DexClassLoader 这两个Android专用的类加载器。
PathClassLoader:只能加载已经安装到Android系统中的apk文件(/data/app目录),是Android默认使用的类加载器。
DexClassLoader:可以加载任意目录下的dex/jar/apk/zip文件,也就是我们一开始提到的补丁。
这两个类都是继承自BaseDexClassLoader,我们可以看一下BaseDexClassLoader的构造函数。
这个构造函数只做了一件事,就是通过传递进来的相关参数,初始化了一个DexPathList对象。DexPathList的构造函数,就是将参数中传递进来的程序文件(就是补丁文件)封装成Element对象,并将这些对象添加到一个Element的数组集合dexElements中去。
ClassLoaer 的加载机制是一种特别聪明的方式,双亲委托机制,在这种机制下,一个Class只会被加载一次。
总的来说,通过DexClassLoader查找一个类,最终就是就是在一个数组中查找特定值的操作。
综合以上所有的观点,我们很容易想到一种非常简单粗暴的热修复方案。假设现在代码中的某一个类或者是某几个类有bug,那么我们可以在修复完bug之后,可以将这些个类打包成一个补丁文件,然后通过这个补丁文件封装出一个Element对象,并且将这个Element对象插到原有dexElements数组的最前端,这样当DexClassLoader去加载类时,优先会从我们插入的这个Element中找到相应的类,虽然那个有bug的类还存在于数组中后面的Element中,但由于双亲加载机制的特点,这个有bug的类已经没有机会被加载了,这样一个bug就在没有重新安装应用的情况下修复了。
策略有所不同,但总的来说都是从上层ClassLoader的角度出发,由于ClassLoader的特点,如果想要新的补丁文件再次生效,无论你是插桩还是提前合并,都需要重新启动应用来加载新的DexPathList。这样就无法在用户神不知鬼不觉的情况下把bug修复了,HotFix在这方面就有绝对的优势了。
AndFix 提供了一种运行时在Native修改Filed指针的方式,实现方法的替换,达到即时生效无需重启,对应用无性能消耗的目的。
由于他是Native层操作,因此如果我们在Java层中新增字段,或者是修改类的方法,他是无能为力的。同时由于Android在国内变成了安卓,各大手机厂商定制了自己的ROM,所以很多底层实现的差异,导致AndFix的兼容性并不是很好。
采用全量替换的思路,从一种更高的层次实现了热修复。应该是现有最成熟的热修复方案了。