概念
我们先假设一个场景,如果一个已经上线的APP中,发现了一些bug,可能你会想直接升级版本就可以了,但是后面如果不断出现bug,难度要用户不断更新吗?这显然不太实际,用户也很难接受。这时“热修复”的概念就油然而生了,我们可以在用户未知或者影响极小的情况下把已知的bug修复,而不需要升级版本。
第三方框架
目前已经存在很多热修复的框架供我们使用了,这里就简单例举下。
阿里系
腾讯系
美团
至于如何选择使用第三方框架,在这不多设篇幅,这篇主要阐述一个热修复的概念和简单实现。
简单实现
了解了热修复的简单概念后,这里不适用第三方框架以一个例子来简单实现一下热修复。
预期效果
准备
dex分包
在Android中,calss文件全部打包进了dex中,程序通过ClassLoader从dex文件中加载需要的类。在用户安装好应用后,我们进行热修复把B.class重新打包进dex是不现实的,所以我们应该先将B.class打包成一个新的dex文件,让程序在加载B.class的时候,是从新的dex文件从加载,而不是从旧的dex文件加载。
因此需要dex分包,mutildex的配置可以使应用支持多包,同时也可以避免65536方法数上限。下面是mutildex的配置 :
app module中build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "22.0.1"
defaultConfig {
applicationId ...
...
// Enabling multidex support.
multiDexEnabled true
}
...
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:multidex:1.0.0'
...
}
}
让自己的Application类继承MultidexApplication,也可以不继承:
public class App extends Application {
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
}
}
实现原理
正如我们所知,Java的类加载是通过ClassLoader进行的,在Android中也差不多,通过BaseDexClassLoader 加载classes.dex。需要实现热修复我们要用到两个BaseDexClassLoader 子类:PathClassLoader 和 DexClassLoader。
分析ClassLoader相关源码
作为一个合格的程序员,当然要先看看这两个类加载器的源码啦?。我们可以直接下载离线的源码,也可以在线查看,我比较懒,选择在线看。附上传送门androidxref.com,这里可以看到所有版本的源码。这里我找的是6.0.0_r1的。
这个类很简单,就一个方法,并且还是调用父类方法,我就不贴上来了,英文好的可以自行看注释,大概意思就是这个类主要用来加载应用当前程序的dex。
这个类也很简单,也看不出什么,和PathClassLoader类似,不过这个可以加载指定dex文件,但需要是在当前应用程序的目录下。
这个类是PathClassLoader和DexClassLoader共同的父类,通过查看这个类源码,我们可以发现 Class<?> findClass(String name)
这个方法,那我们可以猜想,如果 findClass(B)
时,把已经修复好bug的B.class替换有bug的那个返回回去不就实现了热修复了吗?bigo,来看看这个方法:
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
List<Throwable> suppressedExceptions = new ArrayList<Throwable>();
Class c = pathList.findClass(name, suppressedExceptions);
if (c == null) {
ClassNotFoundException cnfe = new