热修复实现原理(三)

热修复实现原理——instant run

一、Instant Run 简介

Instant Run,是android studio2.0新增的一个运行机制,在编码开发、测试或debug的时候,它都能显著减少你对当前应用的构建和部署的时间。

当我们第一次点击run、debug按钮的时候,它运行时间和我们往常一样。但是接下去的时间里,你每次修改代码后点击run、debug按钮,对应的改变将迅速的部署到你正在运行的程序上,传说速度快到你都来不及把注意力集中到手机屏幕上,它就已经做好相应的更改。

正常App 构建流程

热修复实现原理(三)_第1张图片
appBuild_old.png

instant run构建流程

热修复实现原理(三)_第2张图片
appBuild_new.png

也就是 instant run = 增量构建 + 热 或 温 或 冷拔插

  • 热拔插:代码改变被应用、投射到APP上,不需要重启应用,不需要重建当前activity。

    场景:适用于多数的简单改变(包括一些方法实现的修改,或者变量值修改)

  • 温拔插:activity需要被重启才能看到所需更改。

    场景:典型的情况是代码修改涉及到了资源文件,即resources。

  • 冷拔插:app需要被重启(但是仍然不需要重新安装)

    场景:任何涉及结构性变化的,比如:修改了继承规则、修改了方法签名等。

二、Instant Run 原理(以Rubust为例)

Instant-Run代码作为一个宿主程序,将app作为资源dex加载起来,和插件化一个思路

1、编译期

每个产品代码的每个函数都在编译打包阶段自动的插入了一段代码,插入过程对业务开发是完全透明。如State.java的getIndex函数:

//修改前
public long getIndex() {
        return 100;
}
//修改后
    public static ChangeQuickRedirect changeQuickRedirect;
    public long getIndex() {
        if(changeQuickRedirect != null) {
            //PatchProxy中封装了获取当前className和methodName的逻辑,并在其内部最终调用了changeQuickRedirect的对应函数
            if(PatchProxy.isSupport(new Object[0], 
                                    this,
                                    changeQuickRedirect, false)) {
                return ((Long)PatchProxy.accessDispatch(new Object[0],this,
                                                        changeQuickRedirect,
                                                        false)).longValue();
            }
        }
        return 100L;
    }

可以看到Robust为每个class增加了个类型为ChangeQuickRedirect的静态成员,而在每个方法前都插入了使用changeQuickRedirect相关的逻辑,当 changeQuickRedirect不为null时,可能会执行到accessDispatch从而替换掉之前老的逻辑,达到fix的目的。

2、生成Patch

如果需将getIndex函数的返回值改为return 106,那么对应生成的patch,主要包含两个class:PatchesInfoImpl.java和StatePatch.java。

PatchesInfoImpl.java:

public class PatchesInfoImpl implements PatchesInfo {
    public List getPatchedClassesInfo() {
        List patchedClassesInfos = new ArrayList();
        PatchedClassInfo patchedClass = new PatchedClassInfo("com.meituan.sample.d", StatePatch.class.getCanonicalName());
        patchedClassesInfos.add(patchedClass);
        return patchedClassesInfos;
    }
}

StatePatch.java:

public class StatePatch implements ChangeQuickRedirect {
    @Override
    public Object accessDispatch(String methodSignature, Object[] paramArrayOfObject) {
        String[] signature = methodSignature.split(":");
        if (TextUtils.equals(signature[1], "a")) {//long getIndex() -> a
            return 106;
        }
        return null;
    }

    @Override
    public boolean isSupport(String methodSignature, Object[] paramArrayOfObject) {
        String[] signature = methodSignature.split(":");
        if (TextUtils.equals(signature[1], "a")) {//long getIndex() -> a
            return true;
        }
        return false;
    }
}

3、运行期

客户端拿到含有PatchesInfoImpl.java和StatePatch.java的patch.dex后,用DexClassLoader加载patch.dex,反射拿到PatchesInfoImpl.java这个class。拿到后,创建这个class的一个对象。然后通过这个对象的getPatchedClassesInfo函数,知道需要patch的class为com.meituan.sample.d(com.meituan.sample.State混淆后的名字),再反射得到当前运行环境中的com.meituan.sample.d class,将其中的changeQuickRedirect字段赋值为用patch.dex中的StatePatch.java这个class new出来的对象

热修复实现原理(三)_第3张图片
patching.png

三、Instant Run 优劣

  • 相对于只在MutiDex 在运行前 将补丁插入Dex数组 Instant run 提供的方案兼容性更强
  • 但由于 属于新开发的思路,目前对SO、res资源的替换尚未实现。

你可能感兴趣的:(热修复实现原理(三))