阿里 AndFix 热修复框架简介

Posted 蕉下客--)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了阿里 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代码

  1. public class PathClassLoader extends BaseDexClassLoader {
  2. public PathClassLoader(String dexPath, ClassLoader parent) {
  3. super(dexPath, null, null, parent);
  4. }
  5. public PathClassLoader(String dexPath, String libraryPath,
  6. ClassLoader parent) {
  7. super(dexPath, null, libraryPath, parent);
  8. }
  9. }
DexClassLoader代码
  1. public class DexClassLoader extends BaseDexClassLoader {
  2. public DexClassLoader(String dexPath, String optimizedDirectory, String libraryPath, ClassLoader parent) {
  3. super(dexPath, new File(optimizedDirectory), libraryPath, parent);
  4. }
  5. }
两个ClassLoader就两三行代码,只是调用了父类的构造函数.
  1. public class BaseDexClassLoader extends ClassLoader {
  2. private final DexPathList pathList;
  3. public BaseDexClassLoader(String dexPath, File optimizedDirectory,
  4. String libraryPath, ClassLoader parent) {
  5. super(parent);
  6. this.pathList = new DexPathList(this, dexPath, libraryPath, optimizedDirectory);
  7. }
  8. @Override
  9. protected Class<?> findClass(String name) throws ClassNotFoundException {
  10. List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
  11. Class c = pathList.findClass(name, suppressedExceptions);
  12. if (c == null) {
  13. ClassNotFoundException cnfe = new ClassNotFoundException("Didn\'t find class \\"" + name + "\\" on path: " + pathList);
  14. for (Throwable t : suppressedExceptions) {
  15. cnfe.addSuppressed(t);
  16. }
  17. throw cnfe;
  18. }
  19. return c;
  20. }
在BaseDexClassLoader 构造函数中创建一个DexPathList类的实例,这个DexPathList的构造函数会创建一个dexElements 数组

  1. public DexPathList(ClassLoader definingContext, String dexPath, String libraryPath, File optimizedDirectory) {
  2. ...
  3. this.definingContext = definingContext;
  4. ArrayList<IOException> suppressedExceptions = new ArrayList<IOException>();
  5. //创建一个数组
  6. this.dexElements = makeDexElements(splitDexPath(dexPath), optimizedDirectory, suppressedExceptions);
  7. ...
  8. }

然后BaseDexClassLoader 重写了findClass方法,调用了pathList.findClass,跳到DexPathList类中.

  1. /* package */final class DexPathList {
  2. ...
  3. public Class findClass(String name, List<Throwable> suppressed) {
  4. //遍历该数组
  5. for (Element element : dexElements) {
  6. //初始化DexFile
  7. DexFile dex = element.dexFile;
  8. if (dex != null) {
  9. //调用DexFile类的loadClassBinaryName方法返回Class实例
  10. Class clazz = dex.loadClassBinaryName(name, definingContext, suppressed);
  11. if (clazz != null) {
  12. return clazz;
  13. }
  14. }
  15. }
  16. return null;
  17. }
  18. ...
  19. }
会遍历这个数组,然后初始化DexFile,如果DexFile不为空那么调用DexFile类的loadClassBinaryName方法返回Class实例. 
归纳上面的话就是:ClassLoader会遍历这个数组,然后加载这个数组中的dex文件. 
而ClassLoader在加载到正确的类之后,就不会再去加载有Bug的那个类了,我们把这个正确的类放在Dex文件中,让这个Dex文件排在dexElements数组前面即可.


热修复框架AndFix的使用

AndFix:阿里开源的热修复框架AndFix,AndFix是 “Android Hot-Fix”的缩写。它支持Android 2.3到6.0版本,并且支持arm与X86系统架构的设备。完美支持Dalvik与ART的Runtime。AndFix 的补丁文件是以 .apatch 结尾的文件。

我这是用eclipse写的Demo.

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, "补丁文件不存在");
        }

    }
}