声明:本文为博主原创文章,转载请注明出处:小嵩的博客
本系列传送门:
美团热修复 Robust 方案接入(一)
美团热修复 Robust 原理解析(二)
Robust是美团点评技术团队提供的Android热修复解决方案,基于Instant Run方案实现,属于方法级修复。Robust的补丁成功率高达99%,总体而言它是一个比较稳定的热修复方案,对于追求补丁稳定可靠的项目,接入Roubust是一个不错的选择。接下来我们介绍一下如何去接入Robust。
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.meituan.robust:gradle-plugin:0.4.82'
classpath 'com.meituan.robust:auto-patch-plugin:0.4.82'
}
}
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
robust.xml配置文件详细内容:
<resources>
<switch>
<turnOnRobust>trueturnOnRobust>
<manual>falsemanual>
<forceInsert>falseforceInsert>
<catchReflectException>truecatchReflectException>
<patchLog>falsepatchLog>
<proguard>trueproguard>
<useAsm>trueuseAsm>
switch>
<packname name="hotfixPackage">
<name>com.meituanname>
<name>com.sankuainame>
<name>com.dianpingname>
packname>
<exceptPackname name="exceptPackage">
<name>com.meituan.robustname>
<name>com.meituan.sample.extensionname>
exceptPackname>
<patchPackname name="patchPackname">
<name>com.meituan.robust.patchname>
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时,我们需要做如下几个操作:
在打基础包的时候,我们需要保存好mapping及methodsMap.robust文件,在打补丁包时,我们需要将之前保存的这两份文件 放置在app/robus/目录下以供Robust去对比两个版本的差异来生成补丁。
在App的build.gradle下将之前注释掉的’auto-patch-plugin’插件给打开。
改代码时,我们需要在改动的方法上面添加 @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
}
改完代码后,运行和生成线上apk同样的命令,即可生成补丁,补丁目录app/build/outputs/robust/patch.jar
额… 补丁生成成功最后也是会显示build failed的。不过查找log,若出现如上输出,则代表补丁生成成功。
由于Robust并没有提供补丁平台,因此补丁下发的功能,需要自己和团队的后端去协商具体实现方案及策略。app的相关接入代码在PatchManipulateImp类中去实现,可参考官方的demo工程。
Robust入口代码:
new PatchExecutor(getApplicationContext(), new PatchManipulateImp(), new RobustCallBackSample()).start();
这个是自行控制的,一般来说需要尽早执行它。补丁加载完成后,运行到相关修复的代码时,则会走补丁包里面的代码逻辑。
这里需要注意的是,在补丁包未加载成功前就已经执行过的代码,是不会主动去触发替换逻辑的。虽然Robust不需要重启就能让补丁生效,但在加载补丁成功后,还是需要在下次执行到该方法时,才会触发执行补丁代码逻辑。并不是说打完补丁包后,所有修改过的代码逻辑都会立即替换。
到这里我们已经接入Robust并可以通过它实现热修复的功能了。其中有很多细节需要我们注意,包括备份文件、方法注释、执行时机、补丁下发平台的实现流程及策略等。总体而言,如果不考虑增大apk的体积的话,只是简单的修复代码,不用修复so和资源,那么选择Robust是最稳定的。如果需要更全的功能,如so、资源更新等,那么目前来说选择Tinker是一个不错的方案。
通过这篇文章我们知道如何接入并去使用Robust了,但它的实现原理及精髓是什么呢? 秉着格物致知的精神,带着这个问题,下篇文章我们将会重点讲解一下Robust的实现原理及内部源码逻辑。文章链接:美团热修复 Robust 原理解析(二)