深入理解Android插件化技术

  • 时间:
  • 浏览:0

VAInstrumentation类重写了execStartActivity土土办法,相关代码如下:

关于双亲委托更完整版的资料,大伙 也都时需访问我博客日后的介绍:classloader双亲委托模式

理解ProxyActivity代理土土办法主要注意两点:

后来思路是修改资源ID的PP段,对于不同的插件使用不同的PP段,从而区分不同插件的资源。具体实现土土办法一种生活生活生活:

上一步欺骗了系统,让系统以为我本人启动的是一四个多 正常的Activity。当来到图 3.2的第10步时,再将插件的Activity换回来。此时调用的是VAInstrumentation类的newActivity土土办法。

和代码加载同类,插件和主工程的资源关系完整版都是一种生活生活避免土土办法:

我我觉得,关于类加载更完整版的内容,笔者也深入剖析过,都时需查看下面的链接:类加载机制详解

避免土土办法有后来种,以VirtualAPK为例,核心思路如下:

这里要重点说一下DexClassLoader的DexPathList。DexClassLoader重载了findClass土土办法,在加载类完整版都是调用其内内外部的DexPathList去加载。DexPathList是在构造DexClassLoader时生成的,其内内外部中有 了DexFile。如下图所示:

资源id是由8位16进制数表示,表示为0xPPTTNNNN。PP段用来区分包空间,默认只区分了应用资源和系统资源,TT段为资源类型,NNNN段在同一四个多 APK中从0000递增。如下表所示:

下面介绍如可通过hook的土土办法启动插件中的Activity,时需避免以下四个多 那些的间题:

这段代码主后来将Activity中的Resource,Context等对象替添加了插件的相应对象,保证插件Activity在调用涉及到Context的土土办法时都都可不可以正确运行。

一些插件框架在避免Activity时思想大都差不多,无非是这一 种生活土土办法之一可能性两者的结合。在hook时,不同的框架可能性会选折 不同的hook点。如3400的RePlugin框架选折 hook了系统的ClassLoader,即图3.2中构造Activity2的ClassLoader,在判断出待启动的Activity是插件中的时,会调用插件的ClassLoader构造相应对象。另外RePlugin为了系统稳定性,选折 了尽量少的hook,但会 它并没有选折 hook系统的startActivity土土办法来替换intent,后来通过重写Activity的startActivity,但会 其插件Activity是时需继承一四个多 同类PluginActivity的基类的。不过RePlugin提供了一四个多 Gradle插件将插件中的Activity的基类添加了PluginActivity,用户在开发插件Activity时也是没有感知的。

四大组件中Activity的支持是最复杂化的,一些组件的实现原理要简单后来,简要概括如下:

该段代码将主应用线程中的Instrumentation对象替添加了自定义的VAInstrumentation类。在启动和创建插件activity时,该类完整版都是偷偷做一些手脚。

但会 ,只要将插件apk的路径加入到AssetManager中,便都都可不可以实现对插件资源的访问。

区别在于调用父类构造器时,DexClassLoader多传了一四个多 optimizedDirectory参数,这一 目录时需是内内外部存储路径,用来缓存系统创建的Dex文件。而PathClassLoader该参数为null,不可不可以加载内内外部存储目录的Dex文件。后来大伙 都时需用DexClassLoader去加载内外部的apk,用法如下:

对于单DexClassLoader来说,其模型如下:



将插件的DexClassLoader中的pathList合并到主工程的DexClassLoader中。后来 做的好处时,都时需在不同的插件以及主工程间直接互相调用类和土土办法,但会 都时需将不同插件的公共模块抽出来倒进一四个多 common插件中直接供一些插件使用。Small采用的是这一 土土办法。

ClassLoader调用loadClass土土办法加载类,代码如下:

插件化技术最初源于免安装运行apk的想法,这一 免安装的apk都时需理解为插件。支持插件化的app都时需在运行时加载和运行插件,后来 便都时需将app中一些不常用的功能模块做成插件,一方面减小了安装包的大小,我本人面都时需实现app功能的动态扩展。我让你实现插件化,主后来避免下面四个多 那些的间题:

通常大伙 通过Context对象访问资源,光创建出Resource对象还居于问题,但会 还时需一些额外的工作。 对资源访问的不同实现土土办法也时需不同的额外工作。以VirtualAPK的避免土土办法为例。

第一步:创建Resource

具体实现时,可能性AssetManager并完整版都是一四个多 public的类,时需通过反射去创建,但会 次责Rom对创建的Resource类进行了修改,后来时需考虑不同Rom的兼容性。

合并式可能性AssetManager中加入了所有插件和主工程的路径,但会 生成的Resource都时需一同访问插件和主工程的资源。但会 可能性主工程和各个插件完整版都是独立编译的,生成的资源id会居于相同的情況,在访问完整版都是产生资源冲突。

通过给插件apk生成相应的DexClassLoader便都时需访问其中的类,这边又一种生活生活生活避免土土办法,有单DexClassLoader和多DexClassLoader一种生活生活形状。

对于多DexClassLoader形状来说,都时需用下面的模型来标识。



对于每个插件完整版都是生成一四个多 DexClassLoader,当加载该插件中的类时时需通过对应DexClassLoader加载。后来 不同插件的类是隔离的,当不同插件引用了同一四个多 类库的不同版本时,我不多 出那些的间题,RePlugin采用的后来此方案。

execStartActivity中会先去避免隐式intent,可能性该隐式intent匹配到了插件中的Activity,将其转添加显式。日后通过markIntentIfNeeded将待启动的的插件Activity替添加了预先在AndroidManifest中占坑的StubActivity,并将插件Activity的信息保存到该intent中。其中有 个dispatchStubActivity函数,会根据Activity的launchMode选折 具体启动哪个StubActivity。VirtualAPK为了支持Activity的launchMode在主工程的AndroidManifest中对于次责启动模式的Activity都预埋了多个坑位。

独立式时,各个插件的资源是互相隔离的,不过可能性我让你实现资源的共享,时需拿到对应的Resource对象。

插件和主工程的互相调用涉及到以下四个多 那些的间题:

插件调用主工程在构造插件的ClassLoader完整版都是传入主工程的ClassLoader作为父加载器,后来插件是都时需直接都时需通过类名引用主工程的类。

DexPathList的loadClass会去遍历DexFile直到找到时需加载的类。

可能性AndroidManifest中预埋的StubActivity并没有具体的实现类,后来此完整版都是居于ClassNotFoundException。日后在避免异常时取出插件Activity的信息,通过插件的ClassLoader反射构造插件的Activity。

插件化技术都时需说是Android高级工程师所时需具备的技能之一,从2012年插件化概念的提出(Android版本),到2016年插件化的百花争艳,都时需说,插件化技术引领着Android技术的进步。本篇文章转载自腾讯bugly,我我觉得写得不错,转载分享给大伙 。

VirtualAPK在初始化完整版都是调用hookInstrumentationAndHandler,该土土办法hook了系统的Instrumentaiton类,由上文可知该类和Activity的启动息息相关。

第一代:dynamic-load-apk最早使用ProxyActivity这一 静态代理技术,由ProxyActivity去控制插件中PluginActivity的生命周期。该种土土办法缺点明显,插件中的activity时需继承PluginActivity,开发时需小心避免context。而DroidPlugin通过Hook系统服务的土土办法启动插件中的Activity,使得开发插件的过程和开发普通的app没有那些区别,但会 可能性hook不多系统服务,异常复杂化且居于问题稳定。

第二代:为了一同达到插件开发的低侵入性(像开发普通app一样开发插件)和框架的稳定性,在实现原理上完整版都是趋近于选折 尽量少的hook,并通过在manifest中预埋一些组件实现对四大组件的插件化。另外各个框架根据其设计思想都做了不同程度的扩展,其中Small更是做成了一四个多 跨平台,组件化的开发框架。

第三代:VirtualApp比较厉害,都都可不可以完整版模拟app的运行环境,都都可不可以实现app的免安装运行和双开技术。Atlas是阿里今年开源出来的一四个多 结合组件化和热修复技术的一四个多 app基础框架,其广泛的应用与阿里系的各个app,其号称是一四个多 容器化框架。

合并式的资源避免土土办法,会引入资源冲突,原困在于不同插件中的资源id可能性相同,后来避免土土办法后来使得不同的插件资源拥有不同的资源id。

都时需看出ClassLoader加载类时,先查看自身是否是 可能性加载过该类,可能性没有加载过会首先让父加载器去加载,可能性父加载器无法加载该类时才会调用自身的findClass土土办法加载,该机制很大程度上避免了类的重复加载。

插件Activity构伟大的伟大的发明来后,为了都都可不可以保证其正常运行时需做些额外的工作。

下面是比较出名的十2个 开源的插件化框架,按照出显 的时间排序。研究它们的实现原理,都时需大致看出插件化技术的发展,根据实现原理都时需将这十2个 框架划分成了三代。

Android系统通过Resource对象加载资源,下面代码展示了该对象的生成过程。

上述代码是在Activity创建时被调用的(后面 会介绍如可hook Activity的创建过程),在activity被构伟大的伟大的发明来后,时需替换其中的mResources为插件的Resource。可能性独立式时主工程的Resource不可不可以访问插件的资源,后来可能性不做替换,会产生资源访问错误。

在介绍hook土土办法日后,先用一张图简要的介绍下系统是如可启动一四个多 Activity的。

VirtualAPK通过替换了系统的Instrumentation,hook了Activity的启动和创建,省去了手动管理插件Activity生命周期的繁琐,让插件Activity像正常的Activity一样被系统管理,但会 插件Activity在开发时和常规一样,即能独立运行又能作为插件被主工程调用。

注意下上述代码hook了十2个 地方,包括以下十2个 hook点:

替换了主工程context中LoadedApk的mResource对象。

将新的Resource添加到主工程ActivityThread的mResourceManager中,但会 根据Android版本做了不同避免。

第三步:关联resource和Activity

都时需说,插件化技术涉及得非常广泛,其中最核心的后来Android的类加载机制和反射机制,相关原理请大伙 自行百度。

上图列出的是启动一四个多 Activity的主要过程,具体步骤如下:

Android中常用的一种生活生活生活类加载器,DexClassLoader和PathClassLoader,它们都继承于BaseDexClassLoader。相关源码如下:

Android开发中有 一些特殊的类,是由系统创建的,但会 由系统管理生命周期。如常用的四大组件,Activity,Service,BroadcastReceiver和ContentProvider。 仅仅构伟大的伟大的发明那些类的实例是没用的,还时需管理组件的生命周期。其中以Activity最为复杂化,不同框架采用的土土办法后来尽相同。下面以Activity为例完整版介绍插件化如可支持组件生命周期的管理。 大致分为一种生活生活土土办法:

腾讯的qq空间热修复技术正是利用了DexClassLoader的加载机制,将时需替换的类添加到dexElements的前面,后来 系统会使用先找到的修复过的类。

经过上述步骤后,便实现了插件Activity的启动,但会 该插件Activity中我觉得时需那些额外的避免,和常规的Activity一样。那那些的间题来了,日后的onResume,onStop等生命周期咋办呢?答案是所有和Activity相关的生命周期函数,系统完整版都是调用插件中的Activity。原困在于AMS在避免Activity时,通过一四个多 token表示具体Activity对象,而这一 token正是和启动Activity时创建的对象对应的,而这一 Activity被大伙 替添加了插件中的Activity,后来日后AMS的所有调用完整版都是传给插件中的Activity。

做完以上工作后,则都时需在插件的Activity放进心的使用setContentView,inflater等土土办法加载布局了。

第二步:hook主工程的Resource

对于合并式的资源访问土土办法,时需替换主工程的Resource,下面是具体替换的代码。

缺点

ProxyActivity代理的土土办法最早是由dynamic-load-apk提出的,其思想很简单,在主工程放进一四个多 ProxyActivy,启动插件中的Activity完整版都是先启动ProxyActivity,在ProxyActivity中创建插件Activity,并同步生命周期。下图展示了启动插件Activity的过程。



具体的过程如下:

该土土办法我我觉得都都可不可以很好的实现启动插件Activity的目的,但会 可能性开发式侵入性很强,dynamic-load-apk日后的插件化方案很少继续使用该土土办法,后来通过hook系统启动Activity的过程,让启动插件中的Activity像启动主工程的Activity一样简单。