一、背景

调研了一下目前主流的热修复架构主要是两种,

底层替换方案 底层替换方案限制颇多,但时效性最好,加载轻快,立即见效 阿里系的AndFix、Sophix 类加载方案 类加载方案时效性差,需要重新冷启动才能见效,但修复范围广,限制少 QZone超级补丁、微信Tinker

其一是类和资源整体替换方案,QZone超级补丁、微信Tinker就是这种。

利用DexClassLoader在应用启动阶段替换需要替换的Class文件、资源达到修复的目的

优点:方便,直接替换简单干脆,开发新的替换补丁Patch.Apk即可 缺点:只能替换修改后的整个类文件不能局部修改代码,必须重启App,而且有dex分包造成的找不类问题。

其二是底层替换方案,阿里系的AndFix、Sophix是这种。

直接在已经加载的类中native层替换掉原有的方法。

优点:效果立竿见影,不需要重启App 缺点:兼容性差,准备工作复杂,需要对应改动native C++层方法。

 

我建议使用第三方SDK的,优先使用微信Tinker方案,目前有免费可用,其次是阿里的Andfix开源版本,最新的Sophix更好(对比发现应该是目前最好的)但是需要收费。

 

如果我们自己开发我尝试研究了一下第一套方案,也就是类替换的方案,生成Patch.apk或者Pacth.jar。

 

PS:目前的方案只是解决了类文件的替换,后续解决了资源文件替换后会再次更新!!本方案暂时没有解决dex拆包造成的加载class失败问题,后续补充。

二、具体方案

下边是根据第一套方案具体实施的方案和逻辑代码

  • 宿主App流程图

android 热修复源码 android最新热修复_jar

  • 补丁App流程图

android 热修复源码 android最新热修复_jar_02

  • 热修复类逻辑图

android 热修复源码 android最新热修复_jar_03

  • 首先是生成补丁包

      一共就两步: 

      1、利用jar命令 jar cvf F:/output.jar F:/com/a/b/c/d.class 打包class到jar文件,支持多个class空格拼接,也可以用build.gradle建立task自动打包指定目录下的class为指定目录结构的jar。注意jar包一定要包含自身package包结构的目录结构。

      2、使用dex命令 dx --dex --output F:\patch.jar F:\output.jar 打包成dex文件,最后我要用的就是这个patch.jar,最终用于升级的包可以是dex、jar(dex的jar)、apk文件的任何一种。

  • 热更新实现代码

      更新核心类

      HotfixHelper.java

android 热修复源码 android最新热修复_jar_04

      这里我用app-debug.apk直接用改动了代码的工程生成的apk来作为patch包,简单粗暴。

      loadPatch()模拟下载过程,我放到了assets里,复制一下可以相当于下载过程,创建给patch文件生成的dex们用的缓存文件夹和存放apk文件的路径,同时提供加载完成和失败的监听。

      mDexPath为复制的patch文件所在地址,Android10开始不支持放在sdCard,只能放在data下的默认缓存目录(文件、图片、下载等)。

      mCacheDir为解析后dex文件的存放位置。

      因为我是把app-debug.apk这个补丁包放到宿主App的assets中测试的,忽略了下载过程,DexPathUtil只是处理复制assets到App的data目录,所以没有贴代码,正式流程是直接下载到data/app/cache/自己目录下。

android 热修复源码 android最新热修复_android 热修复源码_05

android 热修复源码 android最新热修复_android 热修复源码_06

applyPath()负责加载补丁dex,利用java的反射原理。

android 热修复源码 android最新热修复_android_07

combineArray()负责将补丁dex放到App的最前边。

 

      ReflectUtl.java(反射操作类)

android 热修复源码 android最新热修复_App_08

最精简版本的单dexApp热更方案核心代码完结    

-------------------------------------------------------------------------------------------------------------------

 

       最后是宿主App代码应用

       Application的attachBaseContext方法中loadPatch即可。

       这里使用SharedPreference缓存来标记是否需要热更的。

       前文说的下载准备好apk放到指定目录后直接loadPatch即可。

android 热修复源码 android最新热修复_jar_09

 

 

三、问题梳理

 

1、dex分包,android新加入的odex方案,会导致替换报错,下一期会尝试解决这个问题。

目前我也是依靠这个方法解决这个问题,生成了一个所有类都要引用的类,单独打hack.dex包。

 

2、生成Patch.dex过程比较繁琐,需要简化加入gradle自动化插件,以后会具体讲解生成patch的自动化。