优秀文章搜集

robust 热修复实践

2018-06-29  本文已影响22人  suphu
一、导入项目

在项目根目录的build.gradle下添加

dependencies {
    classpath 'com.android.tools.build:gradle:3.1.2'
    //robust插件
    classpath "com.meituan.robust:gradle-plugin:${robustVersion}"
    classpath "com.meituan.robust:auto-patch-plugin:${robustVersion}"
    
}

gradle.properties添加版本号(或者写死,可以忽略):

#meituan hotfix
robustVersion = 0.4.82

在app目录下的build.gradle下添加

if(isMakeHot.toBoolean()){
    //制作补丁开启
    apply plugin: 'auto-patch-plugin'
}else{
    //生成apk开启
    apply plugin: 'robust'
}

dependencies {
     compile "com.meituan.robust:robust:${robustVersion}"
}

gradle.properties中添加开关,以后打包或者打补丁只要修改这个参数:

#Make a patch please set true
isMakeHot=false
二、配置文件

在app目录下添加robust.xml配置文件,一般修改patchPackname和hotfixPackage就可以了:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <switch>
        <!--true代表打开Robust,请注意即使这个值为true,Robust也默认只在Release模式下开启-->
        <!--false代表关闭Robust,无论是Debug还是Release模式都不会运行robust-->
        <turnOnRobust>true</turnOnRobust>
        <!--<turnOnRobust>false</turnOnRobust>-->

        <!--是否开启手动模式,手动模式会去寻找配置项patchPackname包名下的所有类,自动的处理混淆,然后把patchPackname包名下的所有类制作成补丁-->
        <!--这个开关只是把配置项patchPackname包名下的所有类制作成补丁,适用于特殊情况,一般不会遇到-->
        <!--<manual>true</manual>-->
        <manual>false</manual>

        <!--是否强制插入插入代码,Robust默认在debug模式下是关闭的,开启这个选项为true会在debug下插入代码-->
        <!--但是当配置项turnOnRobust是false时,这个配置项不会生效-->
        <!--<forceInsert>true</forceInsert>-->
        <forceInsert>true</forceInsert>

        <!--是否捕获补丁中所有异常,建议上线的时候这个开关的值为true,测试的时候为false-->
        <catchReflectException>true</catchReflectException>
        <!--<catchReflectException>false</catchReflectException>-->

        <!--是否在补丁加上log,建议上线的时候这个开关的值为false,测试的时候为true-->
        <!--<patchLog>true</patchLog>-->
        <patchLog>false</patchLog>

        <!--项目是否支持progaurd-->
        <proguard>true</proguard>
        <!--<proguard>false</proguard>-->

        <!--项目是否支持ASM进行插桩,默认使用ASM,推荐使用ASM,Javaassist在容易和其他字节码工具相互干扰-->
        <useAsm>true</useAsm>
        <!--<useAsm>false</useAsm>-->
    </switch>

    <!--需要热补的包名或者类名,这些包名下的所有类都被会插入代码-->
    <!--这个配置项是各个APP需要自行配置,就是你们App里面你们自己代码的包名,
    这些包名下的类会被Robust插入代码,没有被Robust插入代码的类Robust是无法修复的-->
    <packname name="hotfixPackage">
        <name>包名</name>
    </packname>

    <!--不需要Robust插入代码的包名,Robust库不需要插入代码,如下的配置项请保留,还可以根据各个APP的情况执行添加-->
    <exceptPackname name="exceptPackage">
        <name>com.meituan.robust</name>
        <name>com.meituan.sample.extension</name>
    </exceptPackname>

    <!--补丁的包名,请保持和类PatchManipulateImp中fetchPatchList方法中设置的补丁类名保持一致( setPatchesInfoImplClassFullName("com.meituan.robust.patch.PatchesInfoImpl")),
    各个App可以独立定制,需要确保的是setPatchesInfoImplClassFullName设置的包名是如下的配置项,类名必须是:PatchesInfoImpl-->
    <patchPackname name="patchPackname">
        <name>cn.superh.patch</name>
    </patchPackname>

    <!--自动化补丁中,不需要反射处理的类,这个配置项慎重选择-->
    <noNeedReflectClass name="classes no need to reflect">

    </noNeedReflectClass>
</resources>

三、思路(需要结合项目的实际情况而定)

先说说我们项目中用的原理

首先,接口方面(和美团建议不一致,也没办法,不是我们写 ~ ),后台小伙伴把热修复接口信息,在每个接口中都会返回,啊~~ 这是要干嘛~,所以我是按这样接口返回来写的。

我们把本地的app版本号和补丁版本号在通过Heads传递给后台,来识别是否需要补丁信息。

1.在网络拦截器中,对response进行处理拦截,获取到热修复信息后,去下载。当然在下载的时候,肯定还有多个接口会返回信息,需要做下处理。

2.需要对修复完的版本,本地保存一份,并缓存版本号信息,下次启动需要加载。

3.补丁版本只能针对某一个大版本(app的版本),不能升级应用后,以前的补丁还应用了。

4.安全性的一些考虑。(目前我们只做了文件MD5验证,没有做加密的操作)

四、具体Demo

https://github.com/super-hu/hotfix_android

五、发布流程
正常发布apk
  1. 修改gradle.properties
isMakeHot=false
  1. 去除掉 之前的修复的bug文件含有 @Modify @Add 的注解(如果有)

  2. 保存好outputs/mapping/环境/mapping.txt、outputs/robust/robust.apkhash 文件


发布补丁

1.修改有bug的方法增加@Modify或新增方法或者类@Add

2.把之前保留的mapping.txt和robust.apkhash,复制到app项目下的robust目录

3.修改gradle.properties

isMakeHot=true

4.修改app目录下的robust配置开关(一般不用动,详细看注释)。

5.执行打包命令,最后会在outputs/robust 下生成patch.jar补丁文件,发布到服务器。


注意事项

1.打补丁文件,如果之前未对代码做混淆,需要自行创建mapping.txt(正式环境都是混淆的,可忽略)

如果你们的app没有使用proguard优化代码,那么一切处理起来都比较简单了,Robust插桩部分与Proguard没有依赖关系,所以Robust插桩部分可以放心使用,至于自动化嘛就需要做一些手脚了:

首先需要创建一个mapping.txt文件,请注意文件的命名哈,然后放到app/robust目录下
其他操作和使用说明中的操作一样,只不过需要你在mapping文件中加入几行,比如说我们需要对com.meituan.mainactivity这个类修改bug 需要在mapping文件添加如下代码:
com.meituan.mainactivity ->com.meituan.mainactivity:
                int field ->field
其中com.meituan.mainactivity就是你要修改的类,field是你类中的任一字段,类中的方法名不需要填写(包括修改的方法),mapping文件只能包含这两行,不能有多余的空行,多余空格也不行

2.支持的修复

支持方法级别的修复,支持静态方法
支持新增方法和类

3.不支持的修复

接口、无方法类、构造方法、抽象方法、native方法、synthetic方法等不插住代码

so不支持:

新增字段
修复构造方法
资源和 so 修复
返回值是 this 的方法支持不太好(需要看情况处理)
可能会出现深度方法内联导致的不可预知的错误(几率很小可以忽略)

4.TODO

没有安全校验,需要在加载补丁之前自己做验证

上一篇 下一篇

猜你喜欢

热点阅读