Tinker热修复原理

1 热修复背景

刚发布的版本出现了严重的Bug,这就需要去解决Bug、测试打包重新发布,这会耗费大量的人力和物力,代价比较大。
已经更正了此前发布版本的Bug,如果下个版本是大版本,那么两个版本之间间隔时间会很长,这样要等到下个大版本发布再修复Bug,而之前版本的Bug会长期的影响用户。

版本升级率不高,并且需要长时间来完成版本迭代,前版本的Bug就会一直影响不升级的用户。
有一些小但是很重要的功能需要在短时间内完成版本迭代,比如节日活动。

正常开发流程与热修复开发流程对比:
在这里插入图片描述

热修复框架分类与对比:
在这里插入图片描述

分类:
阿里系:AndFix、Dexposed、阿里百川、Sophix
腾讯系:微信的Tinker、QQ空间的超级补丁、手Q的QFix
知名公司:美团的Robust、饿了么的Amigo、美丽说蘑菇街的Aceso
其它:RocooFix、Nuwa、AnoleFix

2 代码修复

2.1 底层替换方案

在已加载的类中直接替换原有方法,是在原有类的基础上进行修改,无法实现对原有类进行方法和字段的增减,这样会破坏原有类的结构。
最大问题是不稳定性,直接修改虚拟机方法实体的具体字段来实现的。Android是开源的,不同的手机厂商开源对代码进行修改,所以像Andfix就会出现在部分机型上的热修复失效的现象。

修改ArtMethod

Sophix:全部替换底层的,

2.2 类加载方案

APP重新启动后,让ClassLoader去加载新的类。

热修复优势:
无需重新发布新版本,省时省力。
用户无感知修复,也无需下载最新应用,代价小。
修复成功率高,把损失降到最低。

ClassLoader classLoader = MainActivity.class.getClassLoader();
        while (classLoader != null){
            Log.i("MainActivity123",classLoader.toString());
            classLoader = classLoader.getParent();
        }

输出:

dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.hongx.fixtest-
iWkvfdNvIRqzj51aylqjJg==/base.apk"],nativeLibraryDirectories=
[/data/app/com.hongx.fixtest-iWkvfdNvIRqzj51aylqjJg==/lib/x86, /system/lib]]]

java.lang.BootClassLoader@296bb13

在这里插入图片描述

先看看DexClassLoader和PathClassLoader的区别
参考:https://www.jianshu.com/p/7e30ba5cb9ea
1、DexClassLoader可以加载jar/apk/dex,可以从SD卡中加载未安装的apk
2、PathClassLoader只能加载系统中已经安装过的apk

再看看ClassLoader的loadClass方法

  public Class<?> loadClass(String name) throws ClassNotFoundException {
        return loadClass(name, false);
    }
    protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    c = findClass(name);
                }
            }
            return c;
    }
    protected final Class<?> findLoadedClass(String name) {
        ClassLoader loader;
        if (this == BootClassLoader.getInstance())
            loader = null;
        else
            loader = this;
        return VMClassLoader.findLoadedClass(loader, name);
    }

findLoadedClass可以看出ClassLoader先去加载的是已加载过的,如果未加载过(c == null)时候才会走,则去所有需要冷启动重新启动app后才能生效。

//pathc.dex 放在私有目录下

在这里插入图片描述

3 插桩原理

http://androidxref.com/8.1.0_r33/xref/libcore/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java

在这里插入图片描述

4 Dex分包

4.1 65536限制:

com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536

应用的方法数超过了最大数65536个。因为DVM Bytecode的限制,DVM指令集的方法调用指令invoke-kind索引为16bits,最多能引用65535个方法

4.2 LinearAlloc限制

INSTALL_FAILED_DEXOPT

在安装应用时可能会提示INSTALL_FAILED_DEXOPT,产生的原因就是LinearAlloc限制,DVM中的LinearAlloc是一个固定的缓存区,当方法数超出缓存区的大小时会报错。

为了解决65536限制和LinearAlloc限制,从而产生了Dex分包机制。
Dex分包方案主要做的时在打包时将应用代码分成多个Dex,将应用启动时必须用到的类和这些类的直接引用类放到主Dex中,其它代码放到次Dex中。当应用启动时先加载主Dex,等到应用启动后再动态地加载次Dex,从而缓解了主Dex的65536限制和LinearAlloc限制

4.3 gradle配置

android {
	compileSdkVersion 28
	defaultConfig {
		...
		 // 开启分包
		multiDexEnabled true
		// 设置分包配置文件
		multiDexKeepFile file('multidex.keep')
	}
	...
	dexOptions {
		javaMaxHeapSize "4g"
		preDexLibraries = false
		additionalParameters = [ // 配置multidex参数
                                 '--multi-dex', // 多dex分包
                                 '--set-max-idx-number=50000', // 每个包内方法数上限
                                 '--main-dex-list=' + '/multidex-config.txt', // 打包到主classes.dex的文件列表
                                 '--minimal-main-dex'
		]
	}
}
dependencies {
    ...
    implementation 'com.android.support:multidex:1.0.3'
}

4.4 配置文件multidex.keep

com/hongx/fixtest/BaseActivity.class
com/hongx/fixtest/BaseApplication.class
com/hongx/fixtest/MainActivity.class

4.5 Application重写attachiBaseContext

@Override
protected void attachBaseContext(Context base) {
	super.attachBaseContext(base);
	MultiDex.install(this);
}

Make Project 后查看app/build/outputs/apk/debug/app-debug.apk 多出一个classes.dex里面包含了MainActivity、BaseApplication、BaseActivity

5 未来发展展望

热修复=“黑科技”?

热修复不同于国内APP进程保活这种“黑科技”,让app常驻后台,既耗电又占用内存,浪费很多手机资源。还有APP的推送服务,无节操地对用户进行信息轰炸。还有更无节操的全家桶app。导致Android手机卡顿不堪,这些所谓的“黑科技”都是为了手机厂商的利益而损害用户的体验

而热修复是能够让开发者和用户双赢的。不仅厂商能快速迭代更新app,使功能尽快上线,而且热更新过程用户无感知,节省大量更新时间,提高用户体验。更重要的能保证app的功能稳定,bug能及时修复。

IOS封杀了热修复功能,Android的热修复是否也有可能被干掉呢?

热修复未来是十分乐观的,不仅不会受到封杀,反而会有很大发展空间

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值