文档章节

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

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

前面的文章介绍了动态加载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

粉丝 46
博文 131
码字总数 36559
作品 4
海淀
高级程序员
私信 提问
知识总结 插件化学习 Activity加载分析

现在安卓插件化已经很成熟,可以直接用别人开源的框架实现自己项目,但是学习插件化的实现原理是安卓研发工程师加深安卓系统理解的很好途径。 安卓插件化学习 插件Activity加载方式分析 实现...

常兴E站
2017/05/19
0
0
Android插件化开发,初入殿堂

好久没有写博客了,这次准备写写我这几天的研究成果——Android插件化开发框架CJFrameForAndroid。 背景交代 首先,你需要知道什么是插件化开发。就拿最常见的QQ来说,在第三个界面动态那里有...

kymjs张涛
2014/10/12
0
9
有关Android插件化的一些总结思考

最近几年移动开发业界兴起了「 插件化技术 」的旋风,各个大厂都推出了自己的插件化框架,各种开源框架都评价自身功能优越性,令人目不暇接。随着公司业务快速发展,项目增多,开发资源却有限...

技术小能手
07/20
0
0
Android插件化开发之动态加载技术学习

Android插件化开发之动态加载技术学习 为什么要插件化开发和动态加载呢?我认为原因有三点: 可以实现解耦 可以解除单个dex函数不能超过65535的限制 可以给apk瘦身,比如说360安全卫士,整个...

幸运券发放
05/18
0
0
反插件化:你的应用不是一个插件(转)

本片文章主要翻译国外的一篇文章,原文在这里 摘要 是一种新型的的虚拟化框架,它允许移动应用程序在不安装应用程序的情况下动态加载并启动其应用程序。该技术的初衷是为了解决热修复问题和减...

隔壁老李头
10/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

阿里千万级高性能、高并发架构的经验之谈

架构以及我理解中架构的本质 在开始谈我对架构本质的理解之前,先谈谈对今天技术沙龙主题的个人见解,千万级规模的网站感觉数量级是非常大的,对这个数量级我们战略上 要重 视 它 , 战术上又...

别打我会飞
20分钟前
3
0
Adnroid架构的详细说明

armeabi armeabi是一个非常老的基于ARM的架构。从Android 4.4开始,CDD(compatibility definition)严格要求ARMv7读取CDD文档。 CDD是Google向设备制造商提供的每个Android版本的规范,它包...

CrazyManDF
22分钟前
3
0
微信小程序内嵌网页web-view

web-view 组件是一个可以用来承载网页的容器,会自动铺满整个小程序页面。个人类型与海外类型的小程序暂不支持使用。 客户端 6.7.2 版本开始,navigationStyle: custom 对 <web-view> 组件无...

xiaogg
23分钟前
2
0
单例模式

第一种方式 public class SingletonA { public static final SingletonA INSTANCE = new SingletonA(); private SingletonA(){ //do something }} 第二种方式 public......

wuyiyi
24分钟前
2
0
git: Authentication failed for错误解决

如果push遇到在输入密码是输错后,就会报这个错误fatal: Authentication failed for 解决办法: git config --system --unset credential.helper 之后你在push就会提示输入名称和密码...

落雪飞声
25分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部