热修复 -- Sophix & Tinker

2019-10-27  本文已影响0人  TomyZhang

一、Sophix & Tinker

Sophix & Tinker

二、使用

Sophix使用

Tinker使用

三、原理

代码修复

代码修复有两大主要方案,一种是阿里系的底层替换方案,另一种是腾讯系的类加载方案。这两类方案各有优缺点:

底层替换方案(热替换代码修复:Sophix):
底层替换方案是在已经加载的类中通过动态修改native指针来直接替换原有方法,是在原有类的基础上进行修改的,因而无法实现对原有类进行方法和字段的增减,因为这样将破坏原有类的结构。

底层替换方案

类加载方案(冷启动代码修复:Tinker Sophix):
类加载方案的原理是在App重新启动后让ClassLoader去加载新的类。因为在App启动到一半的时候,所有需要发生变更的类已经被加载过了,在Android系统上是无法对一个类进行卸载的。如果不重启,原有的类还在虚拟机中,就无法加载新类。因此,只有在下次重启的时候,在还没有运行到业务逻辑之前抢先加载补丁中的新类,这样后续访问这个类时,就会被解析为新类,从而达到热修复的目的。

资源修复

Instant Run:
目前市面上的很多资源修复方案基本上都是参考了Instant Run的实现。Instant Run中的资源热修复分为两步:
1.构造一个新的AssetManager,并通过反射调用addAssetPath函数,然后把完整的新资源包加载到AssetManager中。这样就得到了一个含有所有新资源的AssetManager。
2.找到所有之前引用到原有AssetManager的地方,通过反射,把引用出替换为新的AssetManager。

Sophix:
没有直接参考Instant Run的技术,构造了一个package id为0x66的资源包,这个包里只包含需要改变的资源项(原有包里面没有的新增资源,以及原有内容发生了改变的资源),然后直接在原有AssetManager中通过addAssetPath函数添加这个包就可以了。由于补丁包的package id为0x66,不与目前已经加载的地址为0x7f的包冲突,因此直接加载到已有的AssetManager中就可以直接使用了。整个资源替换的方案优势如下:

唯一有个需要注意的地方就是,因为对新的资源的引用是在新代码中,所有资源修复是需要代码修复的支持的。也因此所有资源修复方案必然是附带代码修复的。

so库修复

Java API提供以下两个接口加载一个so库:

so库的修复本质上是对native方法的修复和替换。

Sophix:
采用的是类似类修复反射注入方式。把补丁so库的路径插入到nativeLibraryDirectories数组的最前面,就能够达到加载so库的时候是补丁so库的目录从而修复Bug的目的。采用这种方案,完全由Sophix在启动期间反射注入补丁中的so库,重启生效。

上一篇下一篇

猜你喜欢

热点阅读