导航
导航
文章目录
  1. 1、热修复技术的优势?
  2. 2、主流方案原理分析
    1. Robust
    2. AndFix
  • # QZone
  • Android热更新技术总结

    当前市面的热补丁方案有很多,其中比较出名的有阿里的HotFix、美团的Robust、微信的Tinker以及QZone的超级补丁方案。

    1、热修复技术的优势?

    • 无需重新发版,实时高效热修复
    • 用户无感知修复,无需下载新的应用,代价小
    • 远程调试
    平台 阿里百川HotFix(Sophix) AndFix Tinker Qzone Robust
    即时生效 yes yes no no yes
    性能损耗 较小 较小 较大 较大 较小
    侵入式打包 无侵入式打包 无侵入式打包 依赖侵入式打包 依赖侵入式打包 依赖侵入式打包
    Rom体积 较小 较小 较大 较小 较小
    接入复杂度 傻瓜式接入 比较简单 复杂 比较简单 复杂
    补丁包大小 较小 较小 较小 较大 一般
    全平台支持 yes yes yes yes yes
    类替换 yes yes yes yes no
    so替换 yes no yes no no
    资源替换 yes no yes yes no
    成功率 ? 一般 较高(95.6%) 较高 最高(99.9%)

    可以看到阿里的Sophix有很大优势,阿里系在热修复领域有很多积累,我们可以看下阿里系的热修复技术发展路径,一张表格来说明一下各个版本热修复的差别:

    方案对比 Andfix开源版本 阿里Hotfix 1.X 阿里Hotfix 最新版 (Sophix)
    方法替换 支持,除部分情况[0] 支持,除部分情况 全部支持
    方法增加减少 不支持 不支持 以冷启动方式支持[1]
    方法反射调用 只支持静态方法 只支持静态方法 以冷启动方式支持
    即时生效 支持 支持 视情况支持[2]
    多DEX 不支持 支持 支持
    资源更新 不支持 不支持 支持
    so库更新 不支持 不支持 支持
    Android版本 支持2.3~7.0 支持2.3~6.0 全部支持包含7.0以上
    已有机型 大部分支持[3] 大部分支持 全部支持
    安全机制 加密传输及签名校验 加密传输及签名校验
    性能损耗 低,几乎无损耗 低,几乎无损耗 低,仅冷启动情况下有些损耗
    生成补丁 繁琐,命令行操作 繁琐,命令行操作 便捷,图形化界面
    补丁大小 不大,仅变动的类 小,仅变动的方法 不大,仅变动的资源和代码[4]
    服务端支持 支持服务端控制[5] 支持服务端控制

    说明:
    [0] 部分情况指的是构造方法、参数数目大于8或者参数包括long,double,float基本类型的方法。
    [1] 冷启动方式,指的是需要重启app在下次启动时才能生效。
    [2] 对于Andfix及Hotfix 1.X能够支持的代码变动情况,都能做到即时生效。而对于其他代码变动较大的情况,会走冷启动方式,此时就无法做到即时生效。
    [3] Hotfix 1.X已经支持绝大部分主流手机,只是在X86设备以及修改了虚拟机底层结构的ROM上不支持。
    [4] 由于支持了资源和库,如果有这些方面的更新,就会导致的补丁变大一些,这个是很正常的。并且由于只包含差异的部分,所以补丁已经是最大程度的小了。
    [5] 提供服务端的补丁发布和停发、版本控制和灰度功能,存储开发者上传的补丁包。

    Sophix目前最新版本3.0,收费服务。

    2、主流方案原理分析

    Robust

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

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

    如State.java的getIndex函数:

    public longgetIndex(){

    **return** 100;

    }

    被处理成如下的实现:

    public static ChangeQuickRedirectchangeQuickRedirect;

    public longgetIndex(){

    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;

    }

    简述 :客户端拿到含有PatchesInfoImpl.java和StatePatch.java的patch.dex后,用DexClassLoader加载patch.dex,反射拿到PatchesInfoImpl.java这个class。拿到后,创建这个class的一个对象。然后通过这个对象的getPatchedClassesInfo函数,知道需要patch的class为xxx,再反射得到当前运行环境中的xxx class,将其中的changeQuickRedirect字段赋值为用patch.dex中的StatePatch.java这个class new出来的对象。这就是打patch的主要过程。通过原理分析,其实Robust只是在正常的使用DexClassLoader,所以可以说这套框架是没有兼容性问题的。