天天看点

Android热修复技术——QQ空间补丁方案解析(1)

传统的app开发模式下,线上出现bug,必须通过发布新版本,用户手动更新后才能修复线上bug。随着app的业务越来越复杂,代码量爆发式增长,出现bug的机率也随之上升。如果单纯靠发版修复线上bug,其较长的新版覆盖期无疑会对业务造成巨大的伤害,更不要说大型app开发通常涉及多个团队协作,发版排期必须多方协调。

那么是否存在一种方案可以在不发版的前提下修复线上bug?有!而且不只一种,业界各家大厂都针对这一问题拿出了自家的解决方案,较为著名的有腾讯的tinker和阿里的andfix以及qq空间补丁。网上对上述方案有很多介绍性文章,不过大多不全面,中间略过很多细节。笔者在学习的过程中也遇到很多麻烦。所以笔者将通过接下来几篇博客对上述两种方案进行介绍,力求不放过每一个细节。首先来看下qq空间补丁方案。

大家都知道,我们开发的代码在被编译成class文件后会被打包成一个dex文件。但是dex文件有一个限制,由于方法id是一个short类型,所以导致了一个dex文件最多只能存放65536个方法。随着现今app的开发日益复杂,导致方法数早已超过了这个上限。为了解决这个问题,google提出了multidex方案,即一个apk文件可以包含多个dex文件。

不过值得注意的是,除了第一个dex文件以外,其他的dex文件都是以资源的形式被加载的,换句话说就是在<code>application.oncreate()</code>方法中被注入到系统的<code>classloader</code>中的。这也就为热修复提供了一种可能:将修复后的代码达成补丁包,然后发送到客户端,客户端在启动的时候到指定路径下加载对应dex文件即可。

根据android虚拟机的类加载机制,同一个类只会被加载一次,所以要让修复后的类替换原有的类就必须让补丁包的类被优先加载。接下来看下android虚拟机的类加载机制。

android的类加载机制和jvm加载机制类似,都是通过classloader来完成,只是具体的类不同而已:

Android热修复技术——QQ空间补丁方案解析(1)

android系统通过<code>pathclassloader</code>来加载系统类和主dex中的类。而<code>dexclassloader</code>则用于加载其他dex文件中的类。上述两个类都是继承自<code>basedexclassloader</code>,具体的加载方法是<code>findclass</code>:

从代码中可以看到加载类的工作转移到了<code>pathlist</code>中,<code>pathlist</code>是一个<code>dexpathlist</code>类型,从变量名和类型名就可以看出这是一个维护dex的容器:

<code>dexpathlist</code>的<code>findclass</code>也很简单,<code>dexelements</code>是维护dex文件的数组,每一个item对应一个dex文件。<code>dexpathlist</code>遍历<code>dexelements</code>,从每一个dex文件中查找目标类,在找到后即返回并停止遍历。所以要想达到热修复的目的就必须让补丁dex在<code>dexelements</code>中的位置先于原有dex:

Android热修复技术——QQ空间补丁方案解析(1)
Android热修复技术——QQ空间补丁方案解析(1)

这就是qq空间补丁方案的基本思路,接下来的博文笔者将以一个实际的例子详述qq空间补丁热修复的过程

继续阅读