Android热修复框架之优逆势分析(Hotfix)

从新整理了一篇更详细的,请移步 Android热修复技术原理

Android平台出现了一些优秀的热更新方案,主要能够分为4类:html

  • 基于Instant Run 热插拔方案:美团的Robust(实时修复)

  Robust插件对每一个产品代码的每一个函数都在编译打包阶段自动的插入了一段代码,对方法进行了Hook,相似AOP的方式。android

  • 基于multidex的热修复方案:表明有Qzone的超级补丁、大众点评的Nuwa、百度金融的RocooFix、 饿了么的Amigo和微信的Tinker(也能够修复so和资源)等(从新冷启动修复)

  须要反射更改DexElements,改变Dex的加载顺序,这使得patch须要在下次启动时才能生效,实时性就受到了影响,同时这种方案在android N [speed-profile]编译模式下可能会有问题。git

  • 基于native hook方案:如阿里开源的Andfix和Dexposed(实时修复)

  须要针对dalvik虚拟机和art虚拟机作适配,须要考虑指令集的兼容问题,须要native代码支持,兼容性上会有必定的影响;github

  • 基于阿里混合模式:阿里没有开源的Sophix(兼具实时修复和冷启动修复)

  在Andfix的基础上进行优化和改进,因此具备实时修复特色。在Dex的加载,资源加载上都作了优化,解决了其余热修复框架上面没法解决的痛点。总体作了大量的优化和改进,惟一的遗憾就是不开源,可是也将整套技术方案整理成电子书,也算是一种回馈吧。算法

  相关技术文章编程

阿里Dexposed -- native解决方案

原理:微信

  • 直接在native层进行方法的结构体信息对换,从而实现完美的方法新旧替换,从而实现热修复功能

  他的思想彻底来源于Xposed框架,完美诠释了AOP编程,这里用到最核心的知识点就是在native层获取到指定方法的结构体,而后改变他的nativeFunc字段值,而这个值就是能够指定这个方法对应的native函数指针,因此先从Java层跳到native层,改变指定方法的nativeFunc值,而后在改变以后的函数中调用Java层的回调便可。实现了方法的拦截功能。框架

  • 基于开源框架Xposed实现,是一种AOP解决方案
  • 只Hook App自己的进程,不须要Root权限

优势:ide

  • 即时生效
  • 不须要任何编译器的插桩或者代码改写,对正常运行不引入任何性能开销。这是AspectJ之类的框架无法比拟的优点;
  • 对所改写方法的性能开销也极低(微秒级),基本能够忽略不计;
  • 从工程的角度来看,热补丁仅仅是牛刀小试,它真正的威力在于『线上调试』;
  • 基于Xposed原理实现的AOP不只能够hook本身的代码,还能够hook同进程的Android SDK代码,这也就可让咱们有能力在App中填上Google本身挖的坑。

缺点:函数

  • Dalvik上近乎完美,不支持ART(须要另外的实现方式),因此5.0以上不能用了;
  • 最大挑战在于稳定性与兼容性,并且native异常排查难度更高;
  • 因为没法增长变量与类等限制,没法作到功能发布级别;

相关连接:

阿里AndFix -- native解决方案

原理:

  • 与Dexposed同样都基于开源框架Xposed实现,是一种AOP解决方案

优势:

  • 即时生效
  • 支持dalvik和art(AndFix supports Android version from 2.3 to 7.0, both ARM and X86 architecture, both Dalvik and ART runtime, both 32bit and 64bit.)
  • 与Dexposed框架相比AndFix框架更加轻便好用,在进行热修复的过程当中更加方便了

缺点:

  • 面临稳定性与兼容性问题
  • AndFix不支持新增方法,新增类,新增field等

相关连接:

QQ空间--Dex分包方案(大众点评的Nuwa参考其实现并开源)

原理:

  • 原理是Hook了ClassLoader.pathList.dexElements[]。由于ClassLoader的findClass是经过遍历dexElements[]中的dex来寻找类的。固然为了支持4.x的机型,须要打包的时候进行插桩。
  • 越靠前的Dex优先被系统使用,基于类级别的修复

优势:

  • 不须要考虑对dalvik虚拟机和art虚拟机作适配
  • 代码是非侵入式的,对apk体积影响不大

缺点:

  • 须要下次启动才会生效
  • 最大挑战在于性能,即Dalvik平台存在插桩致使的性能损耗,Art平台因为地址偏移问题致使补丁包可能过大的问题
  • 虚拟机在安装期间为类打上CLASS_ISPREVERIFIED标志是为了提升性能的,咱们强制防止类被打上标志是否会影响性能?这里咱们会作一下更加详细的性能测试.可是在大项目中拆分dex的问题已经比较严重,不少类都没有被打上这个标志。

相关连接:

美团Robust -- Instant Run 热插拔原理

原理:

  • Robust插件对每一个产品代码的每一个函数都在编译打包阶段自动的插入了一段代码,插入过程对业务开发是彻底透明
  • 编译打包阶段自动为每一个class都增长了一个类型为ChangeQuickRedirect的静态成员,而在每一个方法前都插入了使用changeQuickRedirect相关的逻辑,当 changeQuickRedirect不为null时,可能会执行到accessDispatch从而替换掉以前老的逻辑,达到fix的目的。

优势:

  • 几乎不会影响性能(方法调用,冷启动)
  • 支持Android2.3-8.x版本
  • 高兼容性(Robust只是在正常的使用DexClassLoader)、高稳定性,修复成功率高达99.9%
  • 补丁实时生效,不须要从新启动
  • 支持方法级别的修复,包括静态方法
  • 支持增长方法和类
  • 支持ProGuard的混淆、内联、优化等操做

缺点:

  • 代码是侵入式的,会在原有的类中加入相关代码
  • so和资源的替换暂时不支持
  • 会增大apk的体积,平均一个函数会比原来增长17.47个字节,10万个函数会增长1.67M。
  • 会增长少许方法数,使用了Robust插件后,原来能被ProGuard内联的函数不能被内联了

相关连接:

微信Tinker

原理:

  • 服务端作dex差量,将差量包下发到客户端,在ART模式的机型上本地跟原apk中的classes.dex作merge,merge成为一个新的merge.dex后将merge.dex插入pathClassLoader的dexElement,原理类同Q-Zone,为了实现差量包的最小化,Tinker自研了DexDiff/DexMerge算法。Tinker还支持资源和So包的更新,So补丁包使用BsDiff来生成,资源补丁包直接使用文件md5对比来生成,针对资源比较大的(默认大于100KB属于大文件)会使用BsDiff来对文件生成差量补丁。

优势:

  • 支持动态下发代码
  • 支持替换So库以及资源

缺点:

  • 不能即时生效,须要下次启动

微信已知问题:

  • Tinker不支持修改AndroidManifest.xml,Tinker不支持新增四大组件(1.9.0支持新增非export的Activity);
  • 因为Google Play的开发者条款限制,不建议在GP渠道动态更新代码;
  • 在Android N上,补丁对应用启动时间有轻微的影响;
  • 不支持部分三星android-21机型,加载补丁时会主动抛出"TinkerRuntimeException:checkDexInstall failed";
  • 对于资源替换,不支持修改remoteView。例如transition动画,notification icon以及桌面图标。

相关连接:

对比图(来自不一样的地方)

来自微信

来自蘑菇街 Android 热修复探索之路

其余文章

浅谈Android热修复:

http://blog.csdn.net/caihongdao123/article/details/52051799

相关文章
相关标签/搜索