Android 热修复框架对比与原理(一)

前言

在Android应用开发中,热修复技术被越来越多的开发者所使用,也出现了很多热修复框架,比如:AndFix、Tinker、Dexposed和Nuwa等等。如果只是会这些热修复框架的使用那意义并不大,我们还需要了解它们的原理,这样不管热修复框架如何变化,只要基本原理不变,我们就可以很快的掌握它们。这一个系列不会对某些热修复框架源码进行解析,而是讲解热修复框架的通用原理。

1.热修复的产生概述

在开发中我们会遇到如下的情况:                                                                                                                                                                                                                 1.刚发布的版本出现了严重的bug,这就需要去解决bug、测试并打渠道包在各个应用市场上重新发布,这会耗费大量的人力物力,代价会比较大。                                                                                                                                                                                                                                                                    2.已经改正了此前发布版本的bug,如果下一个版本是一个大版本,那么两个版本的间隔时间会很长,这样要等到下个大版本发布再修复bug,这样此前版本的bug会长期的影响用户。                                                                                                                                                                                             

        3.版本升级率不高,并且需要很长时间来完成版本覆盖,此前版本的bug就会一直影响不升级版本的用户。

        4.有一个小而重要的功能,需要短时间内完成版本覆盖,比如节日活动。

为了解决上面的问题,热修复框架就产生了。对于Bug的处理,开发人员不要过于依赖热修复框架,在开发的过程中还是要按照标准的流程做好自测、配合测试人员完成测试流程(因为没有一种框架是完美的,它们也只是适应大部分情况与使用的情况,它们也是有局限性的)。

2.热修复框架的对比

热修复框架的种类繁多,按照公司团队划分主要有以下几种:

类别成员:

                阿里系                AndFix、Dexposed、阿里百川、Sophix

                腾讯系                微信的Tinker、QQ空间的超级补丁、手机QQ的QFix

                知名公司            美团的Robust、饿了么的Amigo、美丽说蘑菇街的Aceso

                其他                    RocooFix、Nuwa、AnoleFix

虽然热修复框架很多,但热修复框架的核心技术主要有三类,分别是代码修复资源修复动态链接库修复,其中每个核心技术又有很多不同的技术方案,每个技术方案又有不同的实现,另外这些热修复框架仍在不断的更新迭代中,可见热修复框架的技术实现是繁多可变的。作为开发需需要了解这些技术方案的基本原理,这样就可以以不变应万变。

部分热修复框架的对比如下表所示。

特性           AndFix     Tinker/Amigo     QQ空间        Robust/Aceso           Sophix 

即时生效            是            否                    否                        是               视情况而定

方法替换            是            是                    是                        是                是       

类替换                否            是                    是                        否                是

类结构修改        否            是                     否                        否                是

资源替换            否            是                     是                        否                是

so替换                否            是                     否                        否                是

支持gradle          否           是                     否                        否                是

支持ART             是            是                    是                       是                是

支持Android7.0  是            是                    是                        是               是

我们可以根据上表和具体业务来选择合适的热修复框架,当然上表的信息很难做到完全准确,因为部分的热修复框架还在不断更新迭代。

从表中也可以发现Tinker和Amigo拥有的特性最多,是不是就选它们呢?也不尽然,拥有的特性多也意味着框架的代码量庞大,我们需要根据业务来选择最合适的,假设我们只是要用到方法替换,那么使用Tinker和Amigo显然是大材小用了。另外如果项目需要即时生效,那么使用Tinker和Amigo是无法满足需求的。对于即时生效,AndFix、Robust和Aceso都满足这一点,这是因为AndFix的代码修复采用了底层替换方案,而Robust和Aceso的代码修复借鉴了Instant Run原理,现在我们就来学习代码修复。

3.热修复框原理

目前代码修复主要有三种原理:底层替换方案类加载方案Instant Run方案

方案                                                                        框架

底层替换                                AndFix、Dexposed、阿里百川、Sophix

类加载                                    微信的Tinker、QQZone、QFix、Amigo、Nuwa

Instant Run                           Robust、Aceso

我们可以从上表发现,各个框架主要是使用什么原理实现。

底层替换原理:

        底层替换就是直接通过Native层类实现即时的更新,但是由于是在Native层类原有上更改,所以有很多修改的限制,比如不能增减方法、字段,只能修改方法内的结果内容,过程如下图。

Android 热修复框架对比与原理(一)_第1张图片

底层替换方案和反射的原理有些关联,ArtMethod结构体就是反射invoke()方法Native中的调用,AndFix采用的是替换ArtMethod结构体中的字段,这样会有兼容问题,因为厂商可能会修改ArtMethod结构体,导致方法替换失败。Sophix采用的是替换整个ArtMethod结构体,这样不会存在兼容问题。。

类加载原理:    

        类加载就是通过Dex分包方案,通过双亲委托模式进行优先加载方式实现类的替换。

Android 热修复框架对比与原理(一)_第2张图片

类加载方案需要重启App后让ClassLoader重新加载新的类,为什么需要重启呢?这是因为类是无法被卸载的,因此要想重新加载新的类就需要重启App,因此采用类加载方案的热修复框架是不能即时生效的。

Instant Run原理:

除了资源修复,代码修复同样也可以借鉴Instant Run的原理, 可以说Instant Run的出现推动了热修复框架的发展。

Instant Run在第一次构建apk时,使用ASM在每一个方法中注入了类似如下的代码:

IncrementalChange localIncrementalChange = $change;//1if(localIncrementalChange !=null) {//2 localIncrementalChange.access$dispatch("onCreate.(Landroid/os/Bundle;)V",newObject[] {this, paramBundle });return; }

其中注释1处是一个成员变量localIncrementalChange ,它的值为$change,$change实现了IncrementalChange这个抽象接口。当我们点击InstantRun时,如果方法没有变化则$change为null,就调用return,不做任何处理。如果方法有变化,就生成替换类,这里我们假设MainActivity的onCreate方法做了修改,就会生成替换类MainActivity$override,这个类实现了IncrementalChange接口,同时也会生成一个AppPatchesLoaderImpl类,这个类的getPatchedClasses方法会返回被修改的类的列表(里面包含了MainActivity),根据列表会将MainActivity的$change设置为MainActivity$override,因此满足了注释2的条件,会执行MainActivity$override的access$dispatch方法,access$dispatch方法中会根据参数”onCreate.(Landroid/os/Bundle;)V”执行MainActivity$override的onCreate方法,从而实现了onCreate方法的修改。

借鉴Instant Run的原理的热修复框架有Robust和Aceso。

总结:

        到这里,我们大概理解了三大热修复大概的原理,下一章我会解读各个框架中的局限性,上文也提到没有一个框架是完美的,所以我们要更好的去理解他们处在怎么样的局限性,以便我们在使用过程中避免不必要的的时间成本。

Android热修复原理(一)热修复框架对比和代码修复

从Instant-Run出发,谈谈Android上的热修复

Instant Run工作原理及用法

Android 热修复原理篇及几大方案比较

你可能感兴趣的:(Android 热修复框架对比与原理(一))