美文网首页
热修复框架对比(Tinker、Robust)

热修复框架对比(Tinker、Robust)

作者: 小懒猴 | 来源:发表于2019-07-02 15:54 被阅读0次

一、框架特性对比

特性 Tinker Robust
即时生效
方法替换
类替换
类结构修改
资源替换
so替换
支持gradle
补丁包大小 较小 一般
Rom体积 较大 较小
成功率 较高 最高

二、补丁包生成对比

1、Tinker

Tinker支持命令行工具和Gradle两种打包方式,更推荐gradle的方式。

1.1、命令行工具生成

命令行工具tinker-patch-cli.jar提供了基准包与新安装包做差异,生成补丁包的功能。具体的命令参数如下:

java -jar tinker-patch-cli.jar -old old.apk -new new.apk -config tinker_config.xml -out output_path

参数与gradle基本一致,新增的sign参数,需要输入签名路径与签名信息。在编译时需要将TINKER_ID插入到AndroidManifest.xml中。例如

<meta-data android:name="TINKER_ID" android:value="tinker_id_b168b32"/>

1.2、Gradle生成

调用assembleDebug编译,生成的基准包保存在build/bakApk中。

bakApk.png

然后修改要修复的代码,生成补丁包前需要修改build.gradle中的三个参数

  • oldApk:基准APK文件
  • applyMapping:基准包的 Proguard mapping.txt 文件路径
  • applyResourceMapping:基准包的资源 R.txt 文件路径

调用tinkerPatchDebug, 补丁包与相关日志会保存在/build/outputs/tinkerPatch/。然后将补丁包patch_signed_7zip.apk推送到手机的sdcard中就可以修复Bug了。

tinkerPatchTask.png

2、Robust

自动化补丁工具

打补丁包前需要保存好mappingmethodsMap.robust文件。打补丁包时,将之前保存的这两份文件放置在app/robus/目录下以供Robust去对比两个版本的差异来生成补丁。

mapping与methodsMap.robust文件.png

在App的build.gradle下将之前注释掉的’auto-patch-plugin’插件给打开,然后就可以修改代码了。

apply plugin: 'com.android.application'
//制作补丁时将下面这个apply打开,auto-patch-plugin紧跟着com.android.application
//apply plugin: 'auto-patch-plugin'
apply plugin: 'robust'

需要改动的方法上面添加@Modify注解,对于Lambda表达式,则需要在修改过的方法里面调用RobustModify.modify()方法。

修改方法前
public void loadData() {
    Log.d("修改方法前");
}
修改方法后
@Modify
public void loadData() {
    Log.d("修改方法后");
}
新增方法
@Add
public void add() {
    Log.d("新增方法");
}

改完代码后,运行和生成线上apk同样的命令,即可生成补丁,补丁目录app/build/outputs/robust/patch.jar,推送到手机的sdcard中就可以修复Bug了。

三、代码修复原理对比

目前有三种修复方案,类加载方案、Instant Run方案和底层替换方案。Tinker使用的是类加载方案,而Robust使用的则是Instant Run的方式。

1、类加载方案(Tinker)

ClassLoader在加载类的过程中,会调用DexPathList的findClass方法,Element中封装了DexFile用于加载Dex文件。

public Class<?> findClass(String name, List<Throwable> suppressed) {
        for (Element element : dexElements) {
            Class<?> clazz = element.findClass(name, definingContext, suppressed);
            if (clazz != null) {
                return clazz;
            }
        }
        if (dexElementsSuppressedExceptions != null) {
            suppressed.addAll(Arrays.asList(dexElementsSuppressedExceptions));
        }
        return null;
    }

当查找class时,遍历dexElements有序数组,通过Element查找到Class,查找到后返回,没有查找到会接着在下一个Element中查找。修改一个有bug的类(Key.class)后,将类(Key.class)打包成包含dex的补丁包Patch.jar放到dexElements数组的第一个元素,当查找类时首先会找到Patch.dex中修改后的类(Key.class),由于ClassLoader的双亲委托模式,将不会再加载后面有bug的类(Key.class),如下图:

ClassLoader查找流程.png

Tinker将新旧APK包做差异生成patch.dex,将patch.dex与apk中的classes.dex合并,再将新的classes.dex放到dexElements数组的第一个元素,以此来替换有bug的类。由于加载后的类是无法删除的,如果重新加载新的类需要重新启动App,所以这种方法无法即时生效。

2、Instant Run方案(Robust)

Robust会在每个类中注入一个静态变量,在方法前插入一段逻辑控制代码。

注入前
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;
 }

获取到补丁后,会创建DexClassLoader加载补丁,通过被修复的类信息找到该类,反射将changeQuickRedirect对象赋值为补丁对象,changeQuickRedirect将不为空,执行到方法时就会调用补丁的方法而不是原方法的逻辑,这样就起到了热修复的目的。

补丁加载.png

四、注意事项

1、Tinker

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

2、Robust

  • 内部类的构造方法是private(private会生成一个匿名的构造函数)时,需要在制作补丁过程中手动修改构造方法的访问域为public
  • 对于方法的返回值是this的情况现在支持不好,比如builder模式,但在制作补丁代码时,可以通过如下方式来解决,增加一个类来包装一下(如下面的B类),
method a(){
  return this;
}

改为

method a(){
  return new B().setThis(this).getThis();
}
  • 字段增加能力内测中,不过暂时可以通过增加新类,把字段放到新类中的方式来实现字段增加能力
  • 新增的类支持包括静态内部类和非内部类
  • 对于只有字段访问的函数无法直接修复,可通过调用处间接修复
  • 构造方法的修复内测中
  • 资源和so的修复内测中

参考文章:
Tinker wiki
Robust wiki
Android热修复原理
Android热更新方案Robust
美团Robust原理解析

相关文章

网友评论

      本文标题:热修复框架对比(Tinker、Robust)

      本文链接:https://www.haomeiwen.com/subject/iklotxtx.html