阿里 AndFix 热修复框架简介
阿里AndFix热修复框架简介
热修复原理:
Android的类加载机制
Android的类加载器分为两种,PathClassLoader和DexClassLoader,两者都继承自BaseDexClassLoader
PathClassLoader代码位于libcore\dalvik\src\main\Java\dalvik\system\PathClassLoader.java
DexClassLoader代码位于libcore\dalvik\src\main\java\dalvik\system\DexClassLoader.java
BaseDexClassLoader代码位于libcore\dalvik\src\main\java\dalvik\system\BaseDexClassLoader.java
PathClassLoader: 用来加载系统类和应用类
DexClassLoader : 用来加载jar、apk、dex文件.加载jar、apk也是最终抽取里面的Dex文件进行加载
看下PathClassLoader代码
public class PathClassLoader extends BaseDexClassLoader {
public PathClassLoader(String dexPath, ClassLoader parent) {
super(dexPath, null, null, parent);
}
public PathClassLoader(String dexPath, String libraryPath,
ClassLoader parent) {
super(dexPath, null, libraryPath, parent);
}
}
public class DexClassLoader extends BaseDexClassLoader {
public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
super(dexPath, new File(optimizedDirectory), libraryPath, parent);
}
}
public class BaseDexClassLoader extends ClassLoader {
private final DexPathList pathList;
public BaseDexClassLoader(String dexPath, File optimizedDirectory,
String libraryPath, ClassLoader parent) {
super(parent);
this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new ClassNotFoundException("Didn't find class \"" + name + "\" on path: " + pathList);
for (Throwable t : suppressedExceptions) {
cnfe.addSuppressed(t);
}
throw cnfe;
}
return c;
}
public DexPathList(ClassLoader definingContext, String dexPath, String libraryPath, File optimizedDirectory) {
...
this.definingContext = definingContext;
ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
//创建一个数组
this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions);
...
}
/* package */final class DexPathList {
...
public Class findClass(String name, List<Throwable> suppressed) {
//遍历该数组
for (Element element : dexElements) {
//初始化DexFile
DexFile dex = element.dexFile;
if (dex != null) {
//调用DexFile类的loadClassBinaryName方法返回Class实例
Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
if (clazz != null) {
return clazz;
}
}
}
return null;
}
...
}
而ClassLoader在加载到正确的类之后,就不会再去加载有Bug的那个类了,我们把这个正确的类放在Dex文件中,让这个Dex文件排在dexElements数组前面即可.
1.把AndFix抽取成library依赖的形式
2.新建一个AndFixDemo项目,依赖AndFix这个library
2.1 新建一个MyApplication继承Application
public class MyApplication extends Application {
private static final String TAG = "MyApplication";
/**
* apatch文件
*/
private static final String APATCH_PATH = "/Dennis.apatch";
private PatchManager mPatchManager;
@Override
public void onCreate() {
super.onCreate();
// 初始化
mPatchManager = new PatchManager(this);
mPatchManager.init("1.0"); // 版本号
// 加载 apatch
mPatchManager.loadPatch();
//apatch文件的目录
String patchFileString = Environment.getExternalStorageDirectory().getAbsolutePath() + APATCH_PATH;
File apatchPath = new File(patchFileString);
if (apatchPath.exists()) {
Log.i(TAG, "补丁文件存在");
try {
//添加apatch文件
mPatchManager.addPatch(patchFileString);
} catch (IOException e) {
Log.i(TAG, "打补丁出错了");
e.printStackTrace();
}
} else {
Log.i(TAG, "补丁文件不存在");
}
}
}
- 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
- 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
实际当中肯定是通过网络接口下载apatch文件,我这里为了方便演示就放在了SD卡根目录
2.2
在MainActivity用一个按钮弹出吐司,上面是有Bug的代码,下面是修正后的代码
分别打包成Bug.apk和NoBug.apk
2.3 . 然后要用到一个生成补丁的工具apkpatch
_MACOSX是给OSX系统用的
.bat是给window系统用的
我用得是.bat
把之前生成的Bug.apk和NoBug.apk,还有打包所使用的keystore文件放到apkpatch-1.0.3目录下
打开cmd,进入到apkpatch-1.0.3目录下,输入如下指令
apkpatch.bat -f NoBug.apk -t Bug.apk -o Dennis -k keystore -p 111111 -a 111111 -e 111111
每个参数含义如下
-f 新版本的apk
-t 旧版本的apk
-o 输出apatch文件的文件夹,可以随意命名
-k 打包的keystore文件名
-p keystore的密码
-a keystore 用户别名
-e keystore 用户别名的密码
如果出现add modified …….就表示成功了,去apkpatch-1.0.3目录看下,新增了Dennis目录
我把这个文件改为Dennis.apatch
2.4
手机装上Bug.apk运行起来
然后把Dennis.apatch 放到SD卡根目录,退出app,再进入,按下按钮
最后附上Demo还有apk和apatch 文件
最新文章
- MyEclipse怎么设置个性化代码注释模板
- (python) 标准模块sys和os的使用
- Spring 常用的一些工具类
- Python 10 —— 杂
- Reapp - 下一代的 Hybrid App 开发框架
- 利用PHPMailer 来完成PHP的邮件发送 #转载自:大菜鸟在云端#
- easyUI学习笔记之tab组件的鼠标事件
- RecyclerView android:layout_width=";match_parent"; 无效
- 读javascript高级程序设计15-Ajax,CORS,JSONP,Img Ping
- SqlDevlepor注册表监听器设置
- [Android Pro] 监听内容提供者ContentProvider的数据变化
- struts2中错误处理
- PHP 一致性哈希算法的一种简单实现
- 每天一个Linux命令(20)--find命令之exec
- [原创]安全系列之端口敲门服务(Port Knocking for Ubuntu 14.04 Server)
- 阅读源码(IV)
- Redis实战 - 3.Hash
- radhat6.6上安装oracle12c RAC (二)
- Mysql建了索引查询很慢
- 使用PDFminer3k解析pdf为文字遇到:WARING:root:GBK-EUC-H
热门文章
- Azure 进阶攻略 | 关于Java 和事件中心的那不得不说的事
- .Net Mvc 返回Json,动态生成EasyUI Tree
- 基于BranchTraceStore机制的CPU执行分支追踪工具 —— CpuWhere [修正版 仅驱动]
- Gym 100883J	palprime(二分判断点在凸包里)
- 用”人话”解释CNN —— 对单个特征图进行视觉化
- 【414】Code::Blocks增加主题
- getpwuid和getpwnam的用法
- 歌乐第二弹:C++九九八十一
- ios retain copy 以及copy协议
- js转换金钱为中文单位元、万元、亿元、万亿