天天看点

android-plugmgr源代码分析

在正式开始分析源代码之前,我们首先需要有一些动态加载Apk的基础知识。

<a href="http://blog.csdn.net/singwhatiwanna/article/details/22597587">《Android apk动态加载机制的研究》</a>

总的说来,为了调用另一个apk中的类,我们就需要用Android中提供的ClassLoader,将不属于宿主Apk中的类加载进来。由于Android中不允许没有在AndroidManifest中声明的Activity被运行,所以我们需要在AndroidManifest中声明一个代理Activity(ProxyActivity).这篇文章中的思路是,在插件的Activity中将这个ProxyActivity传进去,这样代码执行的逻辑是插件Activity的,同时插件Activity也因为ProxyActivity拥有了部分系统资源的访问能力。这里不是指Resource的访问而是Context所拥有的访问其他组件、与服务交互的能力。当然,插件Activity也存在生命周期函数没法被系统调用、无法访问Resource的问题。

这篇文章解决资源访问的思路是,通过构造Resource对象及其依赖的AssetManager,将资源重定向到插件Apk,然后Override插件中getResource方法。解决生命周期函数无法调用的方法是在ProxyActivity的每一个生命周期函数调用的时候同时调用插件Activity的对应函数。

这个框架只需要在如下面截图中的指定文件夹(一般是sdcard中的Download文件夹)中放入需要动态加载的APK文件,选择对应的图标就可以实现动态加载了.

android-plugmgr源代码分析

1、加载插件信息

从上面我们看到插件的信息通过文件地址dirText传入,然后由 plugMgr.loadPlugin(new File(dirText))进行apk信息的加载,最终将信息保存在plugInfo的集合。plugMgr是一个PluginManager类型的对象,它定义在android_plugmgr类库中。PlugListViewAdapter(继承自BaseAdapter)就是一个带有PlugInfo的Adatpter而已。

2、点击每一项,加载对应的插件

android-plugmgr源代码分析

ActivityClassGenerator: 动态生成 插件Activity子类的工具类

ActivityOverider :提供公共方法供自动生成的Activity调用

FrameworkClassLoader 框架类加载器(Application 的 classLoder被替换成此类的实例),它主要是对插件、宿主的apk进行分别的处理。

LayoutInflaterWrapper :LayoutInflater 包装器,用来替换某些系统布局

PluginActivityLifeCycleCallback :插件Activity的生命周期方法回调

PluginActivityWrapper :插件Activity的包装类

PluginClassLoader :插件类加载器,实现dex文件生成、加载

PluginContextWrapper :插件Context包装类

PlugInfo :插件信息实体类

PluginManager :插件管理类,提供给外部初始化插件apk、启动Activity的公共借口。

PluginManifestUtil :插件Manifest信息提取类,除提取Manifest信息外,也包括提取插件apk中lib的类库)

PluginPackageManager :这个类库自定义的PackageManager,对PackageManager做了些包装

ReflectionUtils :反射工具类,提供一些常用的反射操作。

XmlManifestReader : AndroidManifest.xml读取类

从前面的分析中,我们知道要加载插件apk中的信息,我们需要加载插件apk中的组件(Activity、service、brocastreceiver)、用DexClassLoader加载Dex文件中信息、修改Resource类的资源指向。要完成以上操作,我们需要读取插件apk包中的AndroidManifest信息,取出一些必要的内容(不单单是从AndroidManifest.xml,还有插件apk本身)。

之前我们忽略了PluginManager的初始化。它的初始化是在宿主APK的MainActivity中进行的。初始化通过PluginManager.getInstance()→PluginManager.init()进行调用。getInstance()所做的就是获取ApplicationContext然后传给init().

android-plugmgr源代码分析
android-plugmgr源代码分析

我们来模拟计算机一步步地执行看看。从"先用起来"那一节,我们知道加载类库会调用androidx.pluginmgr.PluginManager.loadPlugin(...)方法.在这一步里面主要对后面用的到的信息进行加载.从代码里面不管单个还是多个插件都进入PluginManager.buildPlugInfo(...)。

这段函数的思路还是很清晰的,其中我们最为感兴趣的是,加载插件apk究竟需要AndroidManifest什么信息?可以预想到Android四大组件肯定是必须的,权限不是必须的。插件apk的所拥有的权限只能宿主apk中AndroidManifest中的,这是Android的安全机制所保证的。进入PluginManifestUtil.setManifestInfo(...)。

从这个函数中,我们就完成了对插件apk所需要的信息的加载,需要注意的是,android-plugmgr这版的源代码暂时只支持Activity,Service、Receiver都还是不支持的。

从点击主界面点击每一个插件开始,

上面代码就是插件加载Activity的整个过程,然而我们漏掉了插件Activity的加载流程,以及特定的Activity怎么被ProxyActivity继承的过程。接下来分析这个类库中自定义的FrameworkClassloader加载特定类的过程。在上面代码context.startActivity(...)中会对将要start的Activity进行加载,也就是调用ClassLoader进行加载,由于我们已经将宿主apk中application的默认Classloader替换成了FrameworkClassloader,所以在context.startActivity(...)的过程中会调用FrameworkClassLoader.loadClass(...)。上一个流程中调用了FrameworkClassloader.newActivityClassName(...),主要为现在插件apk中Activity的加载埋下伏笔。

看来frameworkClassloader也就是对类的加载进行预处理,真正的处理还在PluginClassLoader.loadActivityClass(...)。

android-plugmgr源代码分析

superClassName = "com.handmark.pulltorefresh.samples.LauncherActivity"

targetClassName = "androidx.pluginmgr.PluginActivity"

pluginId = "sample-3.0.0.apk"

pkgName = "com.handmark.pulltorefresh.samples"

让一个ProxyActivity继承插件Apk中特定的Activity

声明字段

对重要的生命周期方法进行声明,并添加添加ActivityOverride对应的静态方法

override访问资源的函数getResource(...)等Activity自身要提供的公共接口

我们以declareMethod_onCreate(dexMaker, generatedType, superType)进行分析

这段函数所做的事情可以用下面的java代码表示

我们的分析就到这里。这个类库目前也就支持Activity、receiver(最新的实验分支支持)而已,对于Service还是不支持的。

<a href="http://blog.csdn.net/luoshengyang/article/details/6703247">Android应用程序内部启动Activity过程(startActivity)的源代码分析</a>

<a href="http://blog.csdn.net/luoshengyang/article/details/6689748">Android应用程序启动过程源代码分析</a>

<a href="http://my.oschina.net/u/2289564/blog/393252">Direct-Load-apk启动插件的原理</a>

本文转自陈哈哈博客园博客,原文链接http://www.cnblogs.com/kissazi2/p/4526055.html如需转载请自行联系原作者

kissazi2

继续阅读