而我们实际上是不需要插件的apk能独立安装运行的,我们希望插件能独立安装运行的本质目的是节省人力,不要维护两套代码。所以看起来,这里只要引入AOP手段,通过AOP编程修改插件Activity的父类,把插件Activity的父类从系统Activity改成我们想要的普通类就行了。
我们先不说这个AOP手段怎么实现,因为问题还没彻底搞清。我们是真的想让A持有B,A收到什么调用就转调B的什么调用吗?这是我们的真正目的吗?不是的。单纯的只是让插件Activity中的super.onCreate()
调用失效,并不完美。因为这跟插件Activity正常安装运行时还有点不一样。现在插件Activity的onCreate方法的代码就相当于是壳子Activity的onCreate方法的代码的一部分了。比如:
class ShadowActivity {
public void onCreate(Bundle savedInstanceState) {
}
}
class PluginActivity extends ShadowActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println(“Hello World!”);
}
}
class ContainerActivity extends Activity {
ShadowActivity pluginActivity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pluginActivity.onCreate(savedInstanceState);
}
}
上面的ShadowActivity
就是我们前面说的普通类。仔细看一下是不是就相当于ContainerActivity
原本就实现成这样:
class ContainerActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
System.out.println(“Hello World!”);
}
}
只要PluginActivity
是动态加载的,就相当于ContainerActivity
的实现是动态的。但是如果原本PluginActivity
的代码是这样的呢?
class PluginActivity extends ShadowActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
savedInstanceState.clear();
super.onCreate(savedInstanceState);
}
}
显然这种代码在正常安装运行时和插件环境运行时就不一样了。因为变成了:
class ContainerActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
savedInstanceState.clear();
}
}
这说明我们要的不是插件Activity的super.onCreate()
调用不执行,我们是希望插件Activity的super.onCreate()
能够直接指挥壳子Activity什么时候调用super.onCreate()
。而且再想想,这是不是继承关系很像?假如PluginActivity是继承自ContainerActivity的,运行时系统调用的是PluginActivity的实例,那么PluginActivity的super.onCreate()
就会直接指导ContainerActivity什么时候调用super.onCreate()
了。所以我们在这里的真正需求是如何把原本的继承关系用持有关系实现了。所以Shadow是这样实现的:
class ShadowActivity {
ContainerActivity containerActivity;
public void onCreate(Bundle savedInstanceState) {
containerActivity.superOnCreate(savedInstanceState);
}
}
class PluginActivity extends ShadowActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
savedInstanceState.clear();
super.onCreate(savedInstanceState);
}
}
class ContainerActivity extends Activity {
ShadowActivity pluginActivity;
@Override
protected void onCreate(Bundle savedInstanceState) {
pluginActivity.onCreate(savedInstanceState);
}
public void superOnCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}
仔细思考下现在的调用结果,是不是PluginActivity在正常安装运行和插件环境下运行时行为就一致了?
好了,现在就可以考虑怎么实施AOP手段将PluginActivity的父类从系统Activity改为ShadowActivity了。Shadow最终使用的是字节码编辑手段。字节码编辑可以通过Android官方的构建过程中的Transform API来实现,所以这个手段也是利用公开API实现的。关于字节码编辑的细节以后的文章再讲。总之,通过字节码编辑,我们可以在不修改源码的情况下,将插件Activity的父类从系统Activity改为ShadowActivity。从而达到同一份源码应用不同编译选项生成不同的apk,一个能正常安装运行,一个能在插件环境运行。
最后
分享一份工作1到5年以上的Android程序员架构进阶学习路线体系,希望能对那些还在从事Android开发却还不知道如何去提升自己的,还处于迷茫的朋友!
-
阿里P7级Android架构师技术脑图;查漏补缺,体系化深入学习提升
-
**全套体系化高级架构视频;**七大主流技术模块,视频+源码+笔记
有任何问题,欢迎广大网友一起来交流
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!
何问题,欢迎广大网友一起来交流
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!