前言插件技术最初起源于apk免安装运行的思想。这个没有安装的apk可以理解为插件。支持插件的应用可以在运行时加载和运行插件,从而可以将应用中一些不常用的功能模块做成插件。一方面减小了安装包的大小,另一方面可以实现app功能的动态扩展。;今天我们来说说插件一、插件介绍1、插件介绍在Android系统中,应用程序以Apk的形式存在,所有的应用程序都需要安装后才能使用。但实际上,在Android系统中安装应用程序的方式是相当简单的。其实就是将应用程序Apk复制到系统的不同目录下,然后解压so;常见的应用安装目录有:/system/app:系统应用/system/priv-app:系统应用/data/app:用户应用的Apk组成,一个常见的Apk会包含以下几部分:classes.dex:Java代码bytecoderes:资源目录lib:so目录assets:静态资源目录AndroidManifest.xml:Manifest文件其实Android系统打开应用程序后,只是打开一个进程,然后使用ClassLoader将classes.dex加载到进程中执行相应的组件;那么你可能会想到一个问题,既然Android本身也使用了类似的反射,为什么我们不能执行Apk中的代码呢?这其实就是插件的目的,让Apk(主要指Android组件)中的代码无需安装即可运行,可以带来很多好处。最明显的优势其实就是通过网络进行热更新和热修复;2、插件技术难点反映并执行插件Apk中的代码(ClassLoaderInjection),使系统调用插件Apk中的组件(RuntimeContainer),正确识别插件Apk资源(ResourceInjection)3.双亲委派机制ClassLoader调用loadClass方法加载类,代码如下:classes(className);if(clazz==null){ClassNotFoundExceptionsuppressed=null;try{//如果还没有加载,先调用父加载器的loadClassclazz=parent.loadClass(className,false);}catch(ClassNotFoundExceptione){suppressed=e;}if(clazz==null){try{//父加载器未加载,则尝试加载clazz=findClass(className);}catch(ClassNotFoundExceptione){e.addSuppressed(suppressed);Throwe;}}}returnclazz;}可以看出,ClassLoader在加载一个类时,首先检查自己是否已经加载了该类。如果它还没有加载它,它会先让父加载器加载它。如果父加载器无法加载该类,它会调用自己的findClass方法进行加载,这种机制很大程度上避免了类的重复加载;二、插件详解1.ClassLoaderInjection简单来说,在插件场景下,同一个进程中会有多个ClassLoader场景:HostClassLoader:宿主是安装应用,插件是自动的在运行ClassLoader加载时创建;并且由于ClassLoader的双亲委派机制,实际上系统类不会受到ClassLoader类隔离机制的影响,使得宿主Apk可以在宿主进程中使用来自插件的组件类;2.RuntimeContainerClassLoaderinjection之后就可以在宿主进程中使用插件Apk中的类了,但是我们都知道Android组件是通过系统调用启动的,卸载后的Apk中的组件是没有注册AMS的,PMS,就像你直接在插件Apk中使用startActivity启动一个组件,系统会告诉你找不到;我们的方案很简单,就是运行时容器技术,简单的在宿主Apk中放一些空的Android组件,以Activity为例,我在宿主中预置了一个ContainerActivityextendsActivity,注册到AndroidManifest.xml中;它要做的事情很简单,就是帮助我们作为插件Activity的容器,它从我开始Intent接受几个参数,分别是插件的不同信息,如:pluginName;插件ApkPath;pluginActivityName等,其实最重要的就是pluginApkPath和pluginActivityName。ContainerActivity启动时,我们加载插件的ClassLoader和Resource,并反射对应的pluginActivityNameActivity类;当加载完成后,ContainerActivity会做两件事:将系统所有的生命周期回调转发给插件Activity接受Activity方法的系统调用,并转发回系统我们可以通过重写生命周期来完成第一件事情ContainerActivity的方法第二步,我们需要定义一个PluginActivity,然后在插件Apk中写Activity组件的时候,不再让它集成android.app.Activity,而是从我们的PluginActivity中集成,然后replaceitwithbytecode这个操作是自动完成的,后面会讲为什么。我们先看伪代码;publicclassContainerActivityextendsActivity{privatePluginActivitypluginActivity;@OverrideprotectedvoidonCreate(BundlesssavedInstanceState){StringpluginActivityName=getIntent().getString("pluginActivityName","");pluginActivity(NamepluginActivity=PluginActivityLoadthis);if(pluginActivity==null){super.onCreate(savedInstanceState);返回;}pluginActivity.onCreate();}@OverrideprotectedvoidonResume(){if(pluginActivity==null){super.onResume();return;}pluginActivity.onResume();}@OverrideprotectedvoidonPause(){if(pluginActivity==null){super.onPause();return;}pluginActivity.onPause();}//...}publicclassPluginActivity{privateContainerActivitycontainerActivity;publicPluginActivity(ContainerActivitycontainerActivity){this.containerActivity=containerActivity;}@Overridepublic
