0%

第13章:热修复原理

热修复框架的核心技术主要有3类:代码修复、资源修复和动态链接库修复。

资源修复

很多热修复的框架的资源修复参考了Instant Run的资源修复原理,因此我们首先了解下Instant Run 的原理。Instant Run 的资源修复核心逻辑在MonkeyPatcher 的monkeyPatchExistingResources 方法中,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
//com/android/tools/fd/runtime/MonkeyPatcher.java

public static void monkeyPatchExistingResources(Context context,String externalResourceFile,Collection<Activity> activityes){

...
try{
//创建一个新的 AssetManager
AssetManager newAssetManager = (newAssetManager)newAssetManager.class.getConstructor(new Class[0]).newInstance(new Object[0]);//1

Method mAddAssetPath = AssetManager.class.getDeclareMethod("addAssetPath",new Class[] {String.class});//2

mAddAssetPath.setAccessible(true);
//通过反射调用 addAssetPath 方法加载外部的资源( SD 卡)
if (((Integer) mAddAssetPath.invoke(newAssetManager,new Object[]{ externalResourceFile})).intValue () == 0) {//3
throw new IllegalStateException("Could not create new AssetManager");

if{activities != null){
for (Activity activity : activities) {
Resources resources= activity.getResources() ;//4
try {
//反射得到 Resources 的 AssetManager 类型的 mAssets 字段
Field mAssets = Resources.class.getDeclareField("mAssets");//5
mAssets.setAccessible(true );

//将 mAssets 字段的引用替换为新创建的 AssetManager
mAssets.set(resources,newAssetManager) ;//6

//得到 Activity 的 Resources.Theme
Resources.Theme theme = activity.getTheme();
...
//反射得到 Resources.Theme 的 mAssets 字段
Field ma = Resources . Theme.class.getDeclaredField (” mAssets " ) ;
ma.setAccessible(true);

//将 Resources.Theme 的 mAssets 字段替换为 newAssetManager
ma.set(theme,newAssetManager);//7
} catch (Throwable ignore) {

}
}
}

可以看出,在注释1处创建了一个新的AssetManager,之后通过反射调用 addAssetPath 方法加载外部(SD卡)的资源。在注释4处遍历Activity 列表,得到每个Activity 的Resource ,在5处通过反射得到Resources 的AssetManager 类型的mAsset字段,并在注释6处改写mAssets字段的引用为新的 AssetManager。之后,将AssetManager 类型的mAssets 字段的引用全部替换为新创建的 AssetManager。所以,总共就是两个步骤:

  • 创建新的 AssetManager ,通过反射调用 addAssetPath 方法加载外部的资源,这样
    新创建的 AssetManager 就含有了外部资源。
  • 将 AssetManager 类型的 rnAssets 字段的引用全部替换为新创建的 AssetManager。

代码修复

先写到这,后续有空再来。。。

谢谢你的鼓励