文档章节

Android插件化动态加载原理(三)

chunquedong
 chunquedong
发布于 2016/05/21 22:27
字数 724
阅读 731
收藏 3

精选30+云产品,助力企业轻松上云!>>>

前面的文章介绍了动态加载apk包中的代码,本篇介绍如何启动插件中的未注册的Activity。Android系统要求所有的组件都在AndroidManifest.xml中注册。这样比较麻烦,插件中不能增加宿主中没有声明的Activity,很不灵活。要绕过Activity注册的限制也不是没有可能,主要有两种方法。

方案1 代理Activity

能想到的一种简单办法是代理模式,注册一个ProxyActivity,假设插件中未注册的Activity叫做PluginActivty。我们把PluginActivty当做普通的类,手动来维护Activity的生命周期。代码大概像这样:

class ProxyActivity extends Activity {
  Activty pluginActivity;
  @Overrride void onCreate() {
    pluginActivity = (Activity)Class.forName("com.test.PluginActivity").newInstance();
    Reflection.set(pluginActivity, "mBase", this);
    pluginActivity.onCreate();  
  }
  @Overrride void onDestroy() {
    pluginActivity.onDestroy();  
  }
  @Overrride void onTouch(Evnet e) {
    pluginActivity.onTouch(e);
  }
}

在ProxyActivity中,我们使用反射的方法初始化插件中未注册的Activity,并初始化一些属性。然后把系统告诉ProxyActivity的告诉PluginActivity。

这种代理方式有些缺点。有时候不能做到对开发者透明,要遵守一些编码约定。由于不是真正的Activity,有些特殊用法也会导致bug。所以实际上axbase插件框架使用的是第二种方案。

方案2 替换Instrumentation

另外一种方法是hook系统的Instrumentation类。Instrumentation类就像是Android系统天生为Android插件化定制的一样,恰到好处。

通过阅读Android源码ActivityThread.java可知,在每次打开新Activity时,由Instrumentation.newActivity方法负责创建Activity实例。如果我们能重写newActivity方法,我们注册一个叫ActivityStub的Activity组件,在newActivity中判断如果是要创建ActivityStub时创建一个插件的Activity返回给系统。这样达到了挂羊头卖狗肉的效果,成功的绕过了Activity需要注册的限制。代码大概像这样:

class MyInstrumentation extends Instrumentation {
  @Overrride Activity newActivity(ClassLoader cl, String className, Intent intent) {
    if (className.equals(ActivityStub.class.getName())) {
        pluginClassLoader.loadClass("com.test.PluginActivity");
        return (Activity)clazz.newInstance();
    }
    return super.newActivity(cl, className, intent);
  }
}

上面代码中的"com.test.PluginActivity"是写死的一个类名,如果要加载某个其它Activity则可以通过Intent.putExtra传递类名参数。

最后,我们再来看一下如何通过反射来替换掉系统的Instrumentation:

Context contextImpl = ((ContextWrapper) context).getBaseContext();
		Object activityThread = Reflection.getField(contextImpl, "mMainThread");
Reflection.setField(activityThread, "mInstrumentation", instrumentation);

同样是反射修改mMainThread的mInstrumentation为我们自定义的instrumentation对象。

方案3 ClassLoader欺骗

其实还有另外一种方式,就是在ClassLoader中,当请求加载ActivityStub类时,直接返回PluginActivity类,来欺骗系统。这种方式和instrumentation方法类似,只是没有Intent来传递类名参数,可能只能使用静态变量来传递。这里不再详细介绍。

其它关于插件化开发的内容在下篇介绍。 请关注axbasePlugin插件化开发框架Github

chunquedong

chunquedong

粉丝 53
博文 137
码字总数 40741
作品 5
海淀
高级程序员
私信 提问
加载中
请先登录后再评论。

暂无文章

CertBot免费生成HTTPS永久SSL证书 Linux CentOS 6.8

CertBot官网 点它------------------------------------------------------>点我 1:执行以下命令安装certbot-auto: wget https://dl.eff.org/certbot-auto sudo mv certbot-auto /usr/l......

osc_ylezri59
1分钟前
0
0
zabbix4.0完整安装过程

zabbix完整安装过程 我的安装环境 一. 安装LAMP环境 1.1 Linux 1.2 Apache 1.3 Mysql或者使用mariaDB也可以 1.4 php 二 安装zabbix 2.1 下载安装 2.2 配置数据库 2.3 创建表,添加zabbix用户 ...

osc_73pstnki
1分钟前
0
0
初学者的Linux——管理LVM逻辑卷

Linux–管理LVM逻辑卷 文章目录 Linux--管理LVM逻辑卷 LVM 物理卷(Physical Volume,PV) 卷组(Volume Group,VG) 逻辑卷(Logical Volume,LV) 逻辑卷创建实验 创建物理卷,命令:pvcre...

osc_g96tdr1z
2分钟前
0
0
Tomcat Filter之动态注入

前言 最近,看到好多不错的关于“无文件Webshell”的文章,对其中利用上下文动态的注入Filter的技术做了一下简单验证,写一下测试总结,不依赖任何框架,仅想学习一下tomcat的filter。 先放几...

osc_8j0twt2u
3分钟前
0
0
接口测试管理,你不来了解一下?

在日常的开发模式里,前端负责页面和动态脚本的处理,服务端负责业务逻辑和接口的实现。当前端需要服务端提供的接口实现动态数据展示和交时,服务端完成接口开发后会提供一个接口文档给到前端...

osc_0g0vbf0z
3分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部