Android的dex热修复的实现基本原理

546 阅读3分钟

本文通过学习聊聊 APK —— Dex 热修复与 Classpath 总结

将java文件直接运行在JVM和Dalvik中,中讲解了java程序如何在JVM和Dalvik中运行,其中在Android部分实现是,先将java文件转为dex文件,导入至安卓手机中,通过Dalvik对该文件编译运行,实现将java文件运行在手机中功能。本文重点讲解如何利用该功能实现简易热修复的效果。 热修复的根本原理是通过修改DexClassLoader 中dexPathList 的dex顺序,达到热修复的效果。

1.制作带有bug的dex

首先创建一个带有打印bug的类test.java,如下所示:

package xiaohan;
public class Test {
	public  void test (){
		System.out.println("This a BUG!");
	}
}

这里需要注意,由于此类需要在带有main的类中引用,需要自定义一个package,否则无法正常引用该类。

创建一个带有main的主类HelloWorld.java,该类中需要引用Test,通过import的形式引入。

import  xiaohan.Test;
public class HelloWorld {
	public static void main (String [] args){
		Test test = new Test();
		test.test();
	}
}

由于需要加载两个java文件,需要通过以下语句执行,注意cp之后有个 “.”的修饰符。

javac -cp . HelloWorld.java Test.java

在这里插入图片描述
将生成的两个class文件,生成一个dex文件,这例需要注意,如果直接按照之前的语句:

dx --dex --output=xiaohan.dex HelloWorld.class Test.class

则会出现以下错误:

E:\ProgramFiles\Android\build-tools\28.0.3>dx --dex --output=xiaohan.dex HelloWorld.class Test.class

PARSE ERROR:
class name (xiaohan/Test) does not match path (Test.class)
...while parsing Test.class
1 error; aborting

原因是由于在创建Test.java文件时,为其指定了包名为xiaohan,与HelloWorld不在同一包下,因此需要创建一个xiaohan的文件夹,将Test.class拷贝进去,然后执行如下语句:

dx --dex --output=xiaohan.dex HelloWorld.class xiaohan/Test.class

就会生成一个的xiaohan.dex文件,将其拷贝至手机后,运行如下语句:

dalvikvm -cp xiaohan.dex HelloWorld

结果如下:

在这里插入图片描述

2. 制作补丁包

重新创建一个新的test.java文件,修改其内容如下:

package xiaohan;
public class Test {
	public  void test (){
		System.out.println("Fix a BUG!");
	}
}

制作一个新的class文件,注意只需要制作Test.class文件,与HelloWorld.class无关,制作语句如下,去除“.”,包含HelloWorld因为在编译时会报错。

javac -cp HelloWorld.java Test.java

在这里插入图片描述
将新制作的Test.class文件制作成功独立的dex文件,这里命名为new.dex,通过执行如下语句:

dx --dex --output=new.dex  xiaohan/Test.class

该dex的是制作补丁包,只包含test.class文件,不包含HelloWorld.class文件。

将生成的new.dex文件,推送至手机存放HelloWorld.dex的目录下,执行修复后的语句,如下所示。

dalvikvm -cp new.dex:xiaohan.dex  HelloWorld

注意,这里需要将补丁包放置前面,然后再添加xiaohan.dex(包含main的dex文件),否则如果先添加new.dex或者不添加,则无法到达修复效果,如下语句。

dalvikvm -cp xiaohan.dex:new.dex  HelloWorld

在这里插入图片描述
以上只是简单的演示在Dalvik虚拟机中,通过修改DexClassLoader 中dexPathList 的dex加载顺序,实现修复的效果,实际使用中,一般我们的APP是安装在data/data/包名/ 目录下, 如果需要热修复文件,在制作好补丁文件(补丁.dex文件)后推送至应用端,在应用使用时,判断是否有该补丁文件,再通过反射形式,修改dexPathList中补丁包的顺序,实现APP热修复的效果。可参考Android学习——手把手教你实现Android热修复