第一章 热修复技术介绍
1.1 什么是热修复
传统开发流程:
- 重写发布版本代价太高
- 用户下载安装成本太高
- bug修复不及时,用户体验差
有许多开发者找到了合适的解决办法,比如:
- 经常变更的业务用H5独立出来,但是增加了学习成本,并且无法转为H5的代码还是无法修复
- 用插件化的方案,但是学习插件化工具需要的成本也高,对老代码的改造也不是短时间就能完成的
热修复技术:
- 无需重新发版,实时高效热修复
- 用户无感知修复,无需下载新的应用,代价小
- 修复成功率高,把损失降到最低
1.2 技术沉淀
阿里系:
- Dexposed:基于Xposed改进,针对Android Dalvik虚拟机运行的Java Method Hook技术,但无法兼容Android5.0以后的虚拟机
- Andfix:也是一种底层替换的方案,做到了Dalvik和ART的兼容
- Hotfix:结合实际工程中的使用Andfix的经验,推出阿里百川Hotfix,但只提供了代码层面的修复,对于资源和so的修复还未实现
- Sophix:2017年6月推出Sophix,打破了各家纷争的局面,在代码修复,资源修复,so修复方面,都做到了业界领先
其他著名的热修复,但是各自有各自的局限性,补丁过大,效率低下,不够稳定,用起来繁琐:
- 腾讯QQ空间的超级补丁
- 微信的Tinker
- 饿了么的Amigo
- 美团的Robust
1.3 详细比较
Sophix和Tinker与Amigo的比较:
各项指标都占优,唯一不支持的就是四大组件的修复
1.4 技术概览
1.4.1 设计理念
Sophix的设计理念,就是非侵入性
- 最终的实现只有两个生成的新旧apk,唯一要做的就是初始化和请求补丁两行代码
- 不会侵入apk的build流程中
- 不改变任何打包组件
- 不插入任何AOP代码
1.4.2 代码修复
两大方案:
- 阿里系的底层替换,限制很多,但时效性好,加载轻快,立即见效
- 腾讯系的类加载,需要重新冷启动才能生效,但修复范围广,限制少
底层替换方案:
- 在原有类的基础上进行修改,无法对原有类的方法和字段进行增减,方法数的变化伴随着方法索引的变化,这样在访问方法的时候就无法正常地索引到正确的方法了,因为增减会导致无法索引到正确的方法和字段
- 更为严重的就是,比如程序正在运行中,突然某个类加了一个字段,那有可能在之前已经产生了这个类的一个旧的实例,那么新方法用到这个旧的实例对象,去访问新的字段,那么会产生不可预期的结果
- 最最令人诟病的是底层替换的不稳定性,传统的底层替换方式,都是去直接依赖修改虚拟机方法实体的具体字段,比如,改Dalvik方法的jni函数指针、改类或方法的访问权限等,这有一个很严重的问题,由于Android的碎片化,是开源的,不同的手机厂商可能会对这个ArtMethod结构体进行了修改,那么在这些修改过源码的设备上,通用性的替换机制就会出问题。这是不稳定的根源
- 只要保证ArtMethod数组仍是以线性结构排列,就能直接使用于将来的Android8.0,9.0等新版本
类加载方案:
- 在app重新启动后让Classloader去加载新的类,因为在app运行到一半的时候,所有需要发生变更的类已经被加载过了,只有在下次重启的时候,还没走到业务逻辑之前抢先加载补丁中的新类
- QQ空间方案会侵入打包流程、QFix的方案需要获取底层虚拟机的函数,不够稳定可靠,并且无法新增public函数、微信的Tinker方法是完整的全量dex加载,可以很大的节省空间,但是性能消耗比较严重,因此,Tinker方案的时空代价转换的性价比并不高
- 阿里采用的也是全量合成dex的技术,直接利用Android原先的类查找和合成机制,快速合成新的全量dex,这样既不需要处理合成时方法数超过的情况,对于dex的机构也不用进行破坏性重构。重新编排了包中的dex的顺序,大大减少合成补丁的开销
双剑合璧:
- Sophix的代码修复体系正是同事涵盖了这两种方案,两种方案的结合,实现优势互补,完全兼顾的作用
- 在补丁生成阶段,会根据实际代码变动情况进行自动选择,小修改,在底层替换方案的限制内,直接用底层替换方案修复,这样还可以做到代码修复即生效,对于超出底层替换限制的,就使用类加载替换,另外,运行时阶段,Sophix还会判断所运行的机型是否支持底层替换,不支持就走类加载修复,达到更好的兼容性
1.4.3 资源修复
目前市面上的很多资源热修复方案基本上都是参考了Instant Run的实现
Instant Run中的资源热修复分为两步:
- 构造一个新的AssetManager,并通过反射调用addAssetPath,把这个完整的新资源包加入到AssetManager中,这样就得到了一个含有所有新资源的AssetManager。
- 找到所有之前引用到原有AssetManager的地方,通过反射,把引用处替换为AssetManager
阿里的方案:构造了一个package id为0x66的资源包,这个包里只包含了改变了的资源项,然后在原有的AssetManager中addAssetPath这个包就可以了。补丁包里面的资源,只包含原有包里面没有新的包里面有的新增资源,以及原有内容发生了改变的资源。采用了更加优雅的替代方式,直接在原有的AssetManager对象上进行析构和重构,这样所有原先对AssetManager对象的引用是没有发生改变的,所以就不需要像Instant Run那样进行繁琐的修改了
阿里资源修复方案的优势在于:
- 不修改AssetManager的引用处,替换更快更完全
- 不必下发完整包,补丁包中只包含有变动的资源
- 不需要再运行时合成完整包。不占用运行时计算和内存资源
1.4.4 SO库修复
SO库修复本质上是对native方法的修复和替换
阿里采用的是类似类修复反射注入方式,把补丁so库的路径插入到nativeLibraryDirectories数组的最前面,达到加载so库的时候是补丁so库,而不是原来so库的目录,从而达到修复目的。
1.5 本章小结
本章介绍了热修复技术的主要使用场景和为业界带来的变化,详细说明了阿里巴巴推出的热修复解决方案Sophix的由来,以及和其他各大主流方案进行了比较
总结
这章是本书的第一章,不过读起来还是蛮受用的,大体了解了现在热修复技术趋势和要点,内容大都是概念性的,有一部分地方肯定不可能看看简述就能明白的,那么需要在接下来的几章内容好好来探索一番,觉得这本书真的挺不错的!