什么是热修复
热修复(也称热补丁、热修复补丁,英语:hotfix)是一种包含信息的独立的累积更新包,通常表现为一个或多个文件。这被用来解决软件产品的问题(例如一个程序错误)。通常情况下,热修复是为解决特定用户的具体问题而制作。
正常开发流程
热修复开发流程
热修复优势
修复什么
热修复框架的对比
按公司团队划分:
类别 | 成果 |
---|---|
阿里系 | AndFix、Dexposed、阿里百川HotFix(未开源)、Sophix(未开源) |
腾讯系 | 微信的Tinker、QQ空间的超级补丁(未开源)、手机QQ的QFix |
知名公司 | 美团的Robust、饿了么的Amigo、美丽说蘑菇街的Aceso |
其他 | 百度金融的RocooFix、大众点评的Nuwa、AnoleFix |
可见,热修复框架很多,但核心技术只有三类:代码修复、资源修复和动态链接库修复,其中每个核心技术又有很多不同的技术方案,每个技术方案又有不同的实现,另外这些热修复框架仍在不断的更新迭代中,由此可见,热修复框架的技术实现是繁多可变的。
比较出名的修复框架的对比如下:
特性 | AndFix | Tinker | QQ空间 | Robust |
---|---|---|---|---|
即时生效 | 是 | 否 | 否 | 是 |
方法替换 | 是 | 是 | 是 | 是 |
类替换 | 否 | 是 | 是 | 否 |
类结构修改 | 否 | 是 | 否 | 否 |
资源替换 | 否 | 是 | 是 | 否 |
so替换 | 否 | 是 | 否 | 否 |
支持gradle | 否 | 是 | 否 | 否 |
支持ART | 是 | 是 | 是 | 是 |
性能损耗 | 较小 | 较小 | 较小 | 较小 |
补丁包大小 | 一般 | 较小 | 较大 | 一般 |
复杂度 | 复杂 | 较低 | 较低 | 复杂 |
成功率 | 一般 | 较高 | 较高 | 最高 |
支持 Android 版本 | 2.3-7.0 | 2.x-8.x | 2.x-7.x | 2.3-9.x |
从上表中,我们可以发现每个热修复框架各有优缺点,其中美团的Robust支持的 Android 版本可达到9.x,且支持方法级别的修复,包括静态方法,也支持增加方法和类,所以此次着重讲解美团的Robust的部分原理和使用。
美团Robust -- Instant Run 热插拔原理
原理
- Robust插件对每个产品代码的每个函数都在编译打包阶段自动的插入了一段代码,插入过程对业务开发是完全透明
- 编译打包阶段自动为每个class都增加了一个类型为ChangeQuickRedirect的静态成员,而在每个方法前都插入了使用changeQuickRedirect相关的逻辑,当 changeQuickRedirect不为null时,可能会执行到accessDispatch从而替换掉之前老的逻辑,达到fix的目的。
优点
- 支持Android2.3-9.x版本
- 高兼容性、高稳定性,修复成功率高达99.9%
- 补丁实时生效,不需要重新启动
- 支持方法级别的修复,包括静态方法
- 支持增加方法和类
- 支持ProGuard的混淆、内联、优化等操作
缺点
- 代码是侵入式的,会在原有的类中加入相关代码
- 会增大apk的体积,平均一个函数会比原来增加17.47个字节,10万个函数会增加1.67M
- 会增加少量方法数
实战
新建项目并导入相应的包
- 在 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.90'
- 在整个项目的build.gradle加入classpath
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.meituan.robust:gradle-plugin:0.4.90'
classpath 'com.meituan.robust:auto-patch-plugin:0.4.90'
}
}
注:要开启资源压缩,开启混淆,后面需要 mapping.txt 文件。
- 开启资源压缩,开启混淆
buildTypes {
release {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
//为方便调试,debug也开启
debug {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
创建相应文件夹及 robust.xml 文件
最终文件大概图:
- robust 文件夹:存放 methodsMap.robust[build/outputs/robust/methodsMap.robust] 和 mapping.txt[build/outputs/mapping/mapping.txt] 文件;
- robust.xml 文件:一些配置信息,一般直接从官方网站上 copy 一份即可。
如何生成补丁
- 将打出的正式包的 methodsMap.robust 和 mapping.txt 文件存放到 robust 文件夹中,如下:
- 将 App 的 build.gradle 中 auto-patch-plugin 注释打开,如下:
apply plugin: 'com.android.application'
//制作补丁时将这个打开,auto-patch-plugin紧跟着com.android.application
apply plugin: 'auto-patch-plugin'
//apply plugin: 'robust'
- 修改需要修改或增加的文件,添加相关注释(@Modify / @Add);
- 像正常打包一样打包,会出现如下提示:
- 生成的补丁包在 app/build/outputs/robust/patch.jar 位置,如下:
注:生成正式包与补丁,都需要秘钥。
补丁包的引入
- 可手动复制进相应的目录;
- 可通过 adb 导入相应的目录;
- 可下载补丁包至指定的目录。
目前笔者采用的是下载补丁包至指定目录,放置位置可自由设定,笔者设置的目录为:/storage/emulated/0/robust/patch/
注意点
- 需要开启资源压缩,开启混淆;
- 打正式包或补丁,需要秘钥;
- 打补丁需要之前打正式包的 methodsMap.robust 和 mapping.txt 文件;
- robust.xml 中需要在 hotfixPackage 中设置自己的包名;
- 调试的时候,debug需要开启资源压缩和混淆。