Robust接入简单说明

准备


  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主动下载补丁,并加载。
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,258评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,335评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,225评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,126评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,140评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,098评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,018评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,857评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,298评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,518评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,400评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,993评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,638评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,661评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 本篇文章将带大家解析Robust框架热修复原理 主流的热修复框架类型 ClassLoader:将热修复的类放在de...
    Jill_Jia阅读 7,510评论 3 17
  • Robust使用篇 Robust使用相对还是比较简单的.有一些坑可能官方文档里讲的不是那么详细,需要自己踏过去 使...
    A邱凌阅读 1,917评论 0 1
  • 美团热修复的使用 如何集成? 在App的build.gradle,加入如下依赖apply plugin: 'com...
    NamelessCoder阅读 3,494评论 6 9
  • 技术介绍 Robust的实现 流程: 1.集成 Robust,生成 apk。保存期间的混淆文件 mapping.t...
    Z_Liqiang阅读 5,509评论 9 11
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,520评论 16 22