# 手把手教你实现Android热修复
## 前言
最近一段时间看了一些关于Android热修复的知识,比如Andfix,Tinker,Sophix等,看了这些框架的原理,就想着自己能不能手撸一个简单的demo。下面我们就来自己动手实现Android热修复吧。
## 热修复实现原理
所谓热修复就是,在我们应用上线后出现小bug需要及时修复时,不用再发新的安装包,只需要发布补丁包,在客户不知不觉之间修复掉bug,JAVA虚拟机JVM在运行时,加载的是.classes的字节码文件。而Android也有自己的虚拟机Dalvik/ART虚拟机,不过他们加载的是dex文件,但是他们的工作原理都一样,都是经过ClassLoader类加载器。Android在ClassLoader的基础上又定义类PathClassLoader和DexClassLoader,两者都继承自BaseDexClassLoader,下面我们看下他们间的区别:
* `BaseDexClassLoader`源代码位于`libcore\dalvik\src\main\java\dalvik\system\BaseDexClassLoader.java`。
* `PathClassLoader`源代码位于`libcore\dalvik\src\main\Java\dalvik\system\PathClassLoader.java `。他主要用来加载系统类和应用类。
* `DexClassLoader`源代码位于`libcore\dalvik\src\main\java\dalvik\system\DexClassLoader.java`。用来加载jar、apk、dex文件.加载jar、apk也是最终抽取里面的Dex文件进行加载.
![DexClassLoader](https://github.com/Terrybthvi/my_classloader_demo/blob/master/Image/20160630102448728.png)
## 手写Android热修复框架
下面我们一步一步来实现Android热修复。
### 写一个专门带有bug的类
既然要测试热修复,我们肯定要写一个带有bug的类。
```
package com.example.bthvi.mycloassloaderapplication.xxx;
import android.content.Context;
import android.view.View;
import android.widget.Toast;
/**
* bug测试类
*/
public class BugClass {
public BugClass(Context context){
Toast.makeText(context,"这是一个优美的bug!",Toast.LENGTH_SHORT).show();
}
}
```
下面我们要写一个热修复的核心工具类。
### 热修复核心类
```
package com.example.bthvi.mycloassloaderapplication;
import android.content.Context;
import android.os.Environment;
import android.support.annotation.NonNull;
import android.widget.Toast;
import java.io.File;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.HashSet;
import dalvik.system.DexClassLoader;
import dalvik.system.PathClassLoader;
public class FixDexUtil {
private static final String DEX_SUFFIX = ".dex";
private static final String APK_SUFFIX = ".apk";
private static final String JAR_SUFFIX = ".jar";
private static final String ZIP_SUFFIX = ".zip";
public static final String DEX_DIR = "odex";
private static final String OPTIMIZE_DEX_DIR = "optimize_dex";
private static HashSet<File> loadedDex = new HashSet<>();
static {
loadedDex.clear();
}
/**
* 加载补丁,使用默认目录:data/data/包名/files/odex
*
* @param context
*/
public static void loadFixedDex(Context context) {
loadFixedDex(context, null);
}
/**
* 加载补丁
*
* @param context 上下文
* @param patchFilesDir 补丁所在目录
*/
public static void loadFixedDex(Context context, File patchFilesDir) {
// dex合并之前的dex
doDexInject(context, loadedDex);
}
/**
*@author bthvi
*@time 2018/6/25 0025 15:51
*@desc 验证是否需要热修复
*/
public static boolean isGoingToFix(@NonNull Context context) {
boolean canFix = false;
File externalStorageDirectory = Environment.getExternalStorageDirectory();
// 遍历所有的修复dex , 因为可能是多个dex修复包
File fileDir = externalStorageDirectory != null ?
new File(externalStorageDirectory,"007"):
new File(context.getFilesDir(), DEX_DIR);// data/data/包名/files/odex(这个可以任意位置)
File[] listFiles = fileDir.listFiles();
if (listFiles != null){
for (File file : listFiles) {
if (file.getName().startsWith("classes") &&
(file.getName().endsWith(DEX_SUFFIX)
|| file.getName().endsWith(APK_SUFFIX)
|| file.getName().endsWith(JAR_SUFFIX)
|| file.getName().endsWith(ZIP_SUFFIX))) {
loadedDex.add(file);// 存入集合
//有目标dex文件, 需要修复
canFix = true;
}
}
}
return canFix;
}
private static void doDexInject(Context appContext, HashSet<File> loadedDex) {
String optimizeDir = appContext.getFilesDir().getAbsolutePath() +
File.separator + OPTIMIZE_DEX_DIR;
// data/data/包名/files/optimize_dex(这个必须是自己程序下的目录)
File fopt = new File(optimizeDir);
if (!fopt.exists()) {
fopt.mkdirs();
}
try {
// 1.加载应用程序dex的Loader
PathClassLoader pathLoader = (PathClassLoader) appContext.getClassLoader();
for (File dex : loadedDex) {
// 2.加载指定的修复的dex文件的Loader
DexClassLoader dexLoader = new DexClassLoader(
dex.getAbsolutePath(),// 修复好的dex(补丁)所在目录
fopt.getAbsolutePath(),// 存放dex的解压目录(用于jar、zip、apk格式的补丁)
null,// 加载dex时需要的库
pathLoader// 父类加载器
);
// 3.开始合并
// 合并的目标是Element[],重新赋值它的值即可
/**
* BaseDexClassLoader中有 变量: DexPathList pathList
* DexPathList中有 变量 Element[] dexElements
* 依次反射即可
*/
//3.1 准备好pathList的引用
Object dexPathList = getPathList(dexLoader);
Object pathPathList = getPathList(pathLoader);
//3.2 从pathList中反射出element集合
Object leftDexElements = getDexElements(dexPathList);
Object rightDexElements = getDexElements(pathPathList);
//3.3 合并两个dex数组
Object dexElements = combineArray(leftDexElements, rightDexElements);
// 重写给PathList里面的Element[] dexElements;赋值
Object pathList = getPathList(pathLoader);// 一定要重新获取,不要用pathPathList,会报错
setField(pathList, pathList.getClass(), "dexElements", dexElements);
}
Toast.makeText(appContext, "修复完成", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 反射给对象中的属性重新赋值
*/
private static void setField(Object obj, Class<?> cl, String field, Object value) throws NoSuchFieldException, IllegalAccessException {
Field declaredField = cl.getDeclaredField(field);
declaredField.setAccessible(true);
declaredField.set(obj, value);
}
/**
* 反射得到对象中的属性值
*/
private static Object getField(Object obj, Class<?> cl, String field) throws NoSuchFieldException, IllegalAccessException {
Field localField = cl.getDeclaredField(field);
localField.setAccessible(true);
return localField.get(obj);
}
/**
* 反射得到类加载器中的pathList对象
*/
private static Object getPathList(Object baseDexClassLoader) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
return getField(baseDexClassLoader, Class.forNa
没有合适的资源?快使用搜索试试~ 我知道了~
my_classloader_demo-master.7z Native层实现热修复
共1289个文件
flat:503个
json:156个
xml:150个
需积分: 5 0 下载量 76 浏览量
2021-11-11
12:04:10
上传
评论
收藏 5.3MB 7Z 举报
温馨提示
my_classloader_demo-master.7z Native层实现热修复
资源推荐
资源详情
资源评论
收起资源包目录
my_classloader_demo-master.7z Native层实现热修复 (1289个子文件)
proguard-android-optimize.txt-3.5.1 4KB
proguard-defaults.txt-3.5.1 4KB
proguard-android.txt-3.5.1 4KB
1xlrs3TA3QakBQU_xmaZAVETex0= 284KB
1xlrs3TA3QakBQU_xmaZAVETex0= 284KB
3uFBrZYUayNpOKFnozOOuO22+BM= 19KB
_DQC7LHUBu0eq2iQtXbsZPSgFTc= 6KB
_DQC7LHUBu0eq2iQtXbsZPSgFTc= 6KB
AOybOIrg+G8YkyeISr9pGMKl8r4= 59KB
AOybOIrg+G8YkyeISr9pGMKl8r4= 59KB
resources-release.ap_ 1.17MB
app-release.apk 1.49MB
gradlew.bat 2KB
executionHistory.bin 2.18MB
executionHistory.bin 838KB
classAnalysis.bin 566KB
classAnalysis.bin 520KB
fileHashes.bin 178KB
fileHashes.bin 86KB
CMakeDetermineCompilerABI_CXX.bin 80KB
CMakeDetermineCompilerABI_CXX.bin 80KB
CMakeDetermineCompilerABI_C.bin 80KB
CMakeDetermineCompilerABI_C.bin 80KB
feature_tests.bin 79KB
feature_tests.bin 79KB
outputFiles.bin 55KB
sha1-checksums.bin 29KB
taskHistory.bin 23KB
md5-checksums.bin 21KB
taskHistory.bin 21KB
resourceHashesCache.bin 18KB
resourceHashesCache.bin 18KB
feature_tests.bin 14KB
feature_tests.bin 14KB
feature_tests.bin 13KB
feature_tests.bin 13KB
CMakeDetermineCompilerABI_CXX.bin 10KB
CMakeDetermineCompilerABI_CXX.bin 10KB
CMakeDetermineCompilerABI_C.bin 10KB
CMakeDetermineCompilerABI_C.bin 10KB
CMakeDetermineCompilerABI_CXX.bin 9KB
CMakeDetermineCompilerABI_CXX.bin 9KB
CMakeDetermineCompilerABI_C.bin 9KB
CMakeDetermineCompilerABI_C.bin 9KB
CMakeDetermineCompilerABI_CXX.bin 8KB
CMakeDetermineCompilerABI_CXX.bin 8KB
CMakeDetermineCompilerABI_C.bin 8KB
CMakeDetermineCompilerABI_C.bin 8KB
feature_tests.bin 8KB
feature_tests.bin 8KB
last-build.bin 1B
last-build.bin 1B
last-build.bin 1B
bwO5r0BlJSjf8DKJof3V5F6rgGI= 8KB
bwO5r0BlJSjf8DKJof3V5F6rgGI= 8KB
feature_tests.c 762B
feature_tests.c 762B
feature_tests.c 762B
feature_tests.c 762B
feature_tests.c 762B
feature_tests.c 762B
feature_tests.c 762B
feature_tests.c 762B
cmake.check_cache 86B
cmake.check_cache 86B
cmake.check_cache 86B
cmake.check_cache 86B
cmake.check_cache 86B
cmake.check_cache 86B
cmake.check_cache 86B
cmake.check_cache 86B
CiEzw6fqrns1hdgyB2Dp+KB+S7k= 30KB
CiEzw6fqrns1hdgyB2Dp+KB+S7k= 30KB
R$styleable.class 35KB
R$styleable.class 25KB
R$style.class 21KB
R$style.class 21KB
R$attr.class 14KB
R$attr.class 11KB
R$styleable.class 11KB
PermissionUtils.class 7KB
FixDexUtil.class 7KB
R$dimen.class 7KB
R$dimen.class 7KB
R$drawable.class 6KB
R$drawable.class 5KB
R$id.class 5KB
R$color.class 5KB
R$color.class 5KB
FixDexManager.class 5KB
R$id.class 4KB
R$attr.class 3KB
SplashActivity.class 3KB
R$string.class 3KB
R$layout.class 2KB
R$layout.class 2KB
R$string.class 2KB
R$styleable.class 2KB
R$styleable.class 2KB
R$styleable.class 2KB
共 1289 条
- 1
- 2
- 3
- 4
- 5
- 6
- 13
资源评论
独沽一味的猪
- 粉丝: 21
- 资源: 23
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功