美团热修复 Robust 方案接入(一)

版权声明:本文为博主原创文章,转载请注明出处: 小嵩的博客 https://blog.csdn.net/qq_22393017/article/details/82190681

声明:本文为博主原创文章,转载请注明出处:小嵩的博客

方案介绍

Robust是美团点评技术团队提供的Android热修复解决方案,基于Instant Run方案实现,属于方法级修复。Robust的补丁成功率高达99%,总体而言它是一个比较稳定的热修复方案,对于追求补丁稳定可靠的项目,接入Roubust是一个不错的选择。接下来我们介绍一下如何去接入Robust。

一、接入步骤:

1.1 在整个项目的build.gradle加入classpath:

 buildscript {
    repositories {
        jcenter()
    }
    dependencies {
         classpath 'com.meituan.robust:gradle-plugin:0.4.82'
         classpath 'com.meituan.robust:auto-patch-plugin:0.4.82'
   }
}

1.2 在App的build.gradle,应用robust插件, 然后加入compile依赖:

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

注:最新版本以Robust 的 GitHub项目为准,地址:https://github.com/Meituan-Dianping/Robust

1.3 在app项目的src同级目录下配置一份robust.xml文件:

robust.xml

robust.xml配置文件详细内容:

<?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>false</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>com.meituan</name>
        <name>com.sankuai</name>
        <name>com.dianping</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>com.meituan.robust.patch</name>
    </patchPackname>

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

    </noNeedReflectClass>
</resources>

通过以上三个步骤,我们就已经接入Robust,此时就可以正常进行开发工作了。

注意:
在基础包打包前需要在robust.xml配置文件中,设置我们项目需要被插桩的包名或者类名。若没有配置的话,在打补丁包编译时,添加了注解的方法会报以下异常:

Caused by: org.codehaus.groovy.GroovyException: patch method com.example.robust.MainActivity.initView() haven't insert code by Robust.Cannot patch this method, method.signature  ()V
        at com.meituan.robust.autopatch.ReadAnnotation.addPatchMethodAndModifiedClass(ReadAnnotation.groovy:134)
        at com.meituan.robust.autopatch.ReadAnnotation$_scanClassForModifyMethod_closure4.doCall(ReadAnnotation.groovy:85)
        at com.meituan.robust.autopatch.ReadAnnotation.scanClassForModifyMethod(ReadAnnotation.groovy:80)
        at com.meituan.robust.autopatch.ReadAnnotation$_readAnnotation_closure1.doCall(ReadAnnotation.groovy:36)
        ... 49 more

二、修复步骤

通过前面三个接入步骤,我们的APP已经接入了Robust。在打包上线时,会生成一份mapping文件(需要开启混淆规则才会有该文件)以及methodsMap.robust文件(build/output/robust目录下),此时我们需要保存好它,这两个文件在我们修复bug生成补丁包时需要用到。打包上线时的安装包我们称之为基础包,基础包里面的代码Robust已经在打包阶段通过插桩提供了代码修复的功能。

在想要修复bug时,我们需要做如下几个操作:

2.1 拷贝备份文件

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

2.2 apply 补丁插件

在App的build.gradle下将之前注释掉的’auto-patch-plugin’插件给打开。

2.3 修改代码

改代码时,我们需要在改动的方法上面添加 @Modify 注解。对于Lambda表达式,则需要在修改过的方法里面调用RobustModify.modify()方法,普通方法也可以通过调用它来实现。

修复前方法代码:

private void initView() {
        Button btnFix = findViewById(R.id.btn_fix);
        btnFix.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
    }

修复后方法代码:

    @Modify
    private void initView() {
        Button btnFix = findViewById(R.id.btn_fix);
        btnFix.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

            }
        });
        btnFix.setBackgroundColor(ContextCompat.getColor(this,R.color.colorPrimary));
    }

新增方法需要添加@Add注解:

    @Add
    private void testAddMethod() {
     //do something
    }

2.4 生成补丁

改完代码后,运行和生成线上apk同样的命令,即可生成补丁,补丁目录app/build/outputs/robust/patch.jar

patch.png
额… 补丁生成成功最后也是会显示build failed的。不过查找log,若出现如上输出,则代表补丁生成成功。

2.5 下发补丁

由于Robust并没有提供补丁平台,因此补丁下发的功能,需要自己和团队的后端去协商具体实现方案及策略。app的相关接入代码在PatchManipulateImp类中去实现,可参考官方的demo工程。

2.6 加载补丁

Robust入口代码:

new PatchExecutor(getApplicationContext(), new PatchManipulateImp(), new RobustCallBackSample()).start();

这个是自行控制的,一般来说需要尽早执行它。补丁加载完成后,运行到相关修复的代码时,则会走补丁包里面的代码逻辑。

这里需要注意的是,在补丁包未加载成功前就已经执行过的代码,是不会主动去触发替换逻辑的。虽然Robust不需要重启就能让补丁生效,但在加载补丁成功后,还是需要在下次执行到该方法时,才会触发执行补丁代码逻辑。并不是说打完补丁包后,所有修改过的代码逻辑都会立即替换。

总结

到这里我们已经接入Robust并可以通过它实现热修复的功能了。其中有很多细节需要我们注意,包括备份文件、方法注释、执行时机、补丁下发平台的实现流程及策略等。总体而言,如果不考虑增大apk的体积的话,只是简单的修复代码,不用修复so和资源,那么选择Robust是最稳定的。如果需要更全的功能,如so、资源更新等,那么目前来说选择Tinker是一个不错的方案。

通过这篇文章我们知道如何接入并去使用Robust了,但它的实现原理及精髓是什么呢? 秉着格物致知的精神,带着这个问题,下篇文章我们将会重点讲解一下Robust的实现原理及内部源码逻辑。

猜你喜欢

转载自blog.csdn.net/qq_22393017/article/details/82190681