前文介绍了Android中如何在应用中加载一个普通未安装的apk文件,也提到了插件化面临的两个问题。一个是组件的生命周期,一个是资源的加载问题。系列的第二篇我们就从如何静态代理一个Activity,从而偷梁换柱,实现『启动一个未在Manifest中申明的Activity』的目标.
Activity静态代理之生命周期
前面提到,Android系统中对四大组件,例如Activity是有限制的,必须在AndroidManifest.xml文件中进行申明,才能启动并运行。
为了解决这个问题,有两种主流的思想,一种是通过Hook手段,在Android系统检查Activity申明的地方想办法Hook,使得未申明的Activity能够正常运行。另一种办法则是今天我们说的,静态代理。
怎么个『静态代理』呢?
思想也很简单,首先我们明确两个对象,一个是宿主(Host),一个是插件(Plugin).
一句话概述就是,用户以为自己启动的是PluginActivity,实际上启动的是HostActivity,这一步偷梁换日正是我们插件框架做的事。
首先我们实现一个HostActivity,并申明到AndroidManifest.xml中。
1 | public class HostBaseActivity extends FragmentActivity { |
1 | <activity |
然后我们需要定义一个『插件Activity』接口,并给一个默认的实现。目的是要求插件开发实现的Activity必须继承我们插件框架的『插件Activity』。
1 | public interface IPluginActivity { |
然后我们实现IPluginActivity,并作为插件开发Activity的基类。
1 | public class PluginBaseActivity implements IPluginActivity { |
看到这,大家可能明白了我们打算做的事,正如我们前面所说的一样,我们打算用HostBaseActivity去替换PluginBaseActivity。也就是HostBaseActivity『代理』PluginBaseActivity。
但是这样的话,我们遇到了一些问题,最主要的有这两点:
- PluginBaseActivity目前只是一个类,并没有Activity所具有的生命周期。
- PluginBaseActivity被HostBaseActivity代理后,是没有办法直接去加载插件中的资源的。
我们先说第一点,PluginBaseActivity如何才能具有Activity的生命周期呢?很简单,HostBaseActivity在对应的生命周期内,调用一下PluginBaseActivity对应的生命周期的方法就好啦。
1 | public class HostBaseActivity extends FragmentActivity { |
这里只是最简化代码了,实际上HostBaseActivity里是需要通过ClassLoader,通过反射的方式创建一个PluginBaseActivity实例。具体的大家可以参考wangyeming/AndroidPluginFrameDemo中的代码。
其它的方法,比如onActivityResult,onRequestPermissionsResult等方法,根据需要,也可以代理实现。可以看到,我们的PluginBaseActivity从一个冷冰冰的java类,变成了有血有肉,活生生的,有生命周期的安卓Activity类。就像文章封面的图片『提线木偶』一样,PluginBaseActivity只是一个徒有其表的木偶,只有我们给它搭上线(HostBaseActivity调用PluginBaseActivity的接口),才能真正的成为可以活动的小人。
好的,现在我们在插件中可以继承PluginBaseActivity,自定义一个插件的Activity。但这里有一个严峻的问题,我们在插件PluginBaseActivity中,理所应当的可以通过setContentView()等方法加载layout,drawable,string等资源文件。但显然,这些资源是属于插件内的,也就是说,宿主内是无法直接加载这些资源。我们为什么不能直接加载插件apk里面的资源,有没有什么办法可以解决这个问题?下一篇文章,我们一起来研究下插件资源加载的问题。