apk动态加载机制就是在未安装apk的情况下运行外部apk,好酷炫的感觉,这样的好处就是动态部署,热插拔,松耦合,降低应用内存cpu占用,但是实现起来比较复杂。
1. 想要运行apk我们可以通过宿主程序去动态加载apk文件并将其放在自己的进程中执行。首先需要宿主程序到文件系统中去加载apk, 理论上可以用到的有DexClassLoader、PathClassLoader和URLClassLoader。
- DexClassLoader :可以加载文件系统上的jar、dex、apk
- PathClassLoader :可以加载/data/app目录下的apk,这也意味着,它只能加载已经安装的apk
- URLClassLoader :可以加载java中的jar,但是由于dalvik不能直接识别jar,所以此方法在android中无法使用,尽管还有这个类
采用DexClassLoader去加载apk,然后如果没有指定class,就调起主activity,否则调起指定的class。activity被调起的过程是这样的:首先通过类加载器去加载apk中activity的类并创建一个新对象,然后通过反射去调用这个对象的setProxy方法和onCreate方法,setProxy方法的作用是将activity内部的执行全部交由宿主程序中的proxy(也是一个activity),onCreate方法是activity的入口,setProxy以后就调用onCreate方法,这个时候activity就被调起来了。
2. 资源管理:因为插件是在宿主程序中运行的,所以是运行在宿主程序的context中,所以先要使用自己的资源还需要想一些办法。
activity的工作主要是由ContextImpl来完成的, 它在activity中是一个叫做mBase的成员变量。注意到Context中有如下两个抽象方法,看起来是和资源有关的,实际上context就是通过它们来获取资源的,这两个抽象方法的真正实现在ContextImpl中。也即是说,只要我们自己实现这两个方法,就可以解决资源问题了。
|
|
下面看一下如何实现这两个方法
首先要加载apk中的资源:
|
|
说明:加载的方法是通过反射,通过调用AssetManager中的addAssetPath方法,我们可以将一个apk中的资源加载到Resources中,由于addAssetPath是隐藏api我们无法直接调用,所以只能通过反射,下面是它的声明,通过注释我们可以看出,传递的路径可以是zip文件也可以是一个资源目录,而apk就是一个zip,所以直接将apk的路径传给它,资源就加载到AssetManager中了,然后再通过AssetManager来创建一个新的Resources对象,这个对象就是我们可以使用的apk中的资源了,这样我们的问题就解决了。
3. Activity的生命周期:
将activity的大部分生命周期方法提取出来作为一个接口(DLPlugin),然后通过代理activity(DLProxyActivity)去调用插件activity实现的生命周期方法,这样就完成了插件activity的生命周期管理,并且没有采用反射,当我们想增加一个新的生命周期方法的时候,只需要在接口中声明一下同时在代理activity中实现一下即可
以上解决了动态加载的一些基本问题,另外还有很多问题需要一步步实现。
更多详细的内容可以查看singwhatiwanna的csdn博客及github开源项目
http://blog.csdn.net/singwhatiwanna/article/details/39937639
https://github.com/singwhatiwanna/dynamic-load-apk