美文网首页
Robust接入简单说明

Robust接入简单说明

作者: 爱新觉罗詹姆查理斯马丁路德旭 | 来源:发表于2020-12-15 16:48 被阅读0次

准备


  1. 在APP的build.gradle文件中,添加依赖:

    apply plugin: 'com.android.application'
    //制作补丁时将这个打开,auto-patch-plugin紧跟着com.android.application
    //apply plugin: 'auto-patch-plugin'
    apply plugin: 'robust'
     
     
    compile 'com.meituan.robust:robust:0.4.99'
    
  2. 在整个项目的build.gradle中加入

    buildscript {
        repositories {
            jcenter()
        }
        dependencies {
             classpath 'com.meituan.robust:gradle-plugin:0.4.99'
             classpath 'com.meituan.robust:auto-patch-plugin:0.4.99'
       }
    }
    
  3. robust.xml文件拷到src同级目录:

image.png
  1. 实现PatchManipulate.javaRobustCallBack.java两个接口

    1. PatchManipulate.java说明:

      /**
       * Created by hedex on 16/6/20.
       */
      public abstract class PatchManipulate {
          /**
           * 获取补丁列表
           *
           * @param context
           * @return 相应的补丁列表
           */
          protected abstract List<Patch> fetchPatchList(Context context);
      
          /**
           * 验证补丁文件md5是否一致
           * 如果不存在,则动态下载
           *
           * @param context
           * @param patch
           * @return 校验结果
           */
          protected abstract boolean verifyPatch(Context context, Patch patch);
      
          /**
           * 努力确保补丁文件存在,验证md5是否一致。
           * 如果不存在,则动态下载
           *
           * @param patch
           * @return 是否存在
           */
          protected abstract boolean ensurePatchExist(Patch patch);
      }
      

      特别说明: patch.setLocalPath()的字符串参数,必须跟robust.xml配置的patchPackname字段中的字符串一致,并且类名一定要是 PatchesInfoImpl

    2. RobustCallBack.java方法说明:

      /**
       * Created by hedex on 17/1/22.
       */
      
      public interface RobustCallBack {
          /**
           * 获取补丁列表后,回调此方法
           *
           * @param result 补丁
           * @param isNet  补丁
           */
          void onPatchListFetched(boolean result, boolean isNet, List<Patch> patches);
      
      
          /**
           * 在获取补丁后,回调此方法
           *
           * @param result 结果
           * @param patch  补丁
           */
          void onPatchFetched(boolean result, boolean isNet, Patch patch);
      
      
          /**
           * 在补丁应用后,回调此方法
           *
           * @param result 结果
           * @param patch  补丁
           */
          void onPatchApplied(boolean result, Patch patch);
      
      
          void logNotify(String log, String where);
      
      
          void exceptionNotify(Throwable throwable, String where);
      }
      

使用


  1. 基础包的预插桩

    基础包的预插桩配置主要在robust.xml文件中配置,主要包括:

    标签 说明
    turnOnRobust 是否打开Robust(只在Release模式下有效)
    forceInsert 是否强制插入代码。如果为true,则在debug模式下,也会插入代码
    catchReflectException 是否捕获补丁中所有异常, (建议上线的时候这个开关的值为true)
    patchLog 是否在补丁加上log, (建议上线的时候这个开关的值为false)
    proguard 项目是否支持proguard,(如果与项目配置不一致,打包时会出错)
    useAsm 插桩是否使用ASM,否则使用javaassist (默认使用ASM,推荐使用ASM,Javaassist在容易和其他字节码工具相互干扰)
    forceInsertLambda 针对Java8级别的Lambda表达式,编译为private级别的javac函数,此时由开发者决定是否进行插桩处理
    <packname name="hotfixPackage"> 需要插桩的包名,或者类名
    <exceptPackname name="exceptPackage"> 不需要插桩的包名,或者类名
    <patchPackname name="patchPackname"> 补丁的包名,(这里设置的包名,必须和PatchManipulateImp中fetchPatchList方法中设置的补丁类名保持一致)

    准备就绪后,在安装或者输出APK时,Robust就会在build/outputs/robust/目录下输出methodsMap.robustmapping.txt。这两个文件非常重要,在打包输出后一定要和APK一起保存。

  2. 打补丁包

    1. 在修改代码之前,需要确定需要打补丁的APK是哪个版本,并将对应的methodsMap.robustmapping.txt文件拷贝到app/robust文件下。

    2. 将APP的build.gradle中的加入

      //制作补丁时将这个打开,auto-patch-plugin紧跟着com.android.application
      apply plugin: 'auto-patch-plugin'
      
    3. 然后开始修改需要修改的代码:

      1. 支持方法,类的新增 ------------@Add 或者 RobustModify.modify()
      2. 方法的修改 ------------------------@Modify
      3. 支持新增字段暂时在内测,可以通过新增类来实现
    4. 运行程序(安装,编译或者打APK操作都可以)

      这次操作会失败,目的只是为了生成patch.jar文件,会抛出java.lang.RuntimeException: auto patch end successfully

  3. 下发补丁 && 补丁包加载

    生成补丁包之后,然后就是如何将patch.jar下发到线上应用上,或者说,线上应用如何得到补丁包。在Demo演示阶段,是将patch.jar 直接push到手机上,但是线上我们就需要让应用自己将补丁包下载到本地,并自动加载补丁包。

    1. 在应用冷启动时,需要检查是否有新的补丁包,如果有,则下载,之后,验证本地补丁包是否有效,并加载所有补丁包
    2. 在应用处于运行阶段,如果有补丁包更新,需要Push推送,提醒应用主动拉新补丁包,并加载新的补丁包

总结


优点

  1. 由于使用的ASM技术插桩,Classloader进行的类加载,所以高兼容,高稳定性
  2. 补丁可以实时加载,实时生效
  3. 支持ProGuard的混淆,内联,优化等操作

缺点

  1. 代码是侵入式的,会在原有的类中加入相关代码
  2. 会增大apk的体积,平均一个函数会比原来增加17.47个字节,10万个函数会增加1.67M

  1. 目前0.4.99对最新的Gradle 6.5是不支持的(issue

  2. Gradle 3.6及以上的版本默认启用了R8,会将插入的changeQuickRedirect变量优化掉,需要在混淆文件proguard-rules.pro中加入以下代码:

    -keepclassmembers class **{ public static com.meituan.robust.ChangeQuickRedirect *;}
    
  3. 对于方法的返回值是this的情况现在支持不好,比如builder模式, 但在制作补丁代码时,可以通过如下方式来解决,增加一个类来包装一下(如下面的B类)

    method a(){
      return this;
    }
    

    改为

    method a(){
      return new B().setThis(this).getThis();
    }
    
  4. 不支持构造方法的修复

  5. 不支持资源和SO的修复

使用时需要注意的点 (每一步的操作都不复杂,但是容易漏掉步骤)

  1. 打基础包时,如果需要在Debug插桩,需要将打开robust.xml中的forceInsert设置成true
  2. 打完基础包之后的methodsMap.robustmapping.txt需要与APK包一起保存,方便查找
  3. 打补丁包时:将对应的methodsMap.robustmapping.txt拷贝到app/robust目录,打开apply plugin: 'auto-patch-plugin'自动化打包插件

小结:

  1. 如果项目对热修复要求不高,只是需要更新一些Java层代码,并且考虑到稳定性,兼容性,Robust都是一个不错的热修复方案。
  2. 目前Robust方案,美团只是开源的代码热修复方案:前期的基础包插桩,以及补丁的自动化,对于补丁的加载策略并没有具体的方案,并没有像Sophix一样提供服务,只是预留了接口。具体的方案需要根据不同的需求自己实现
    1. 是让CI持续集成自动打补丁包(应该是不能交给CI去做)
    2. 本地修改后,直接打补丁包,手动上传到服务器 (涉及到一个服务器的问题,需要一个服务器去管理我们的补丁包)
  3. 是否需要支持热更新,如果需要,服务器还需要提供push推送服务,当有新的补丁包时,需要推送给APP,让APP主动下载补丁,并加载。

相关文章

网友评论

      本文标题:Robust接入简单说明

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