文档章节

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

chunquedong
 chunquedong
发布于 2016/05/21 22:27
字数 724
阅读 554
收藏 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

粉丝 45
博文 131
码字总数 36559
作品 4
海淀
高级程序员
Android插件化开发,初入殿堂

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

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

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

技术小能手
07/20
0
0
Android插件化快速入门与实例解析(VirtualApk)必须了解一下

 集成一个第三方相册功能,只需集成一个插件APK到项目中,无需集成额外代码,并且支持随时更新相册功能,无需发布版本更新,无需AndroidManifest中声明四大组件,这就是插件化。   插件化...

android自学
07/22
0
0
Android插件化开发之动态加载技术学习

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

幸运券发放
05/18
0
0
我的Android重构之旅:插件化篇

随着项目的不断成长,即便项目采用了 MVP 或是 MVVM 这类优秀的架构,也很难跟得上迭代的脚步,当 APP 端功能越来越庞大、繁琐,人员不断加入后,牵一发而动全局的事情时常发生,后续人员如同...

codeGoogle
07/09
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 识别慢性能的宏

Page Profiling 给你了有关页面在载入的时候操作缓慢的邪教,你可以将下面的内容添加到调试(debug)级别: Version 3.1 及其后续版本 设置包名字为 com.atlassian.renderer.v2.components.M...

honeymose
9分钟前
0
0
day93-20180920-英语流利阅读-待学习

时尚之觞:外表光鲜靓丽,其实穷得要命 Lala 2018-09-20 1.今日导读 讲到时尚界,我们脑海里浮现的可能都是模特和设计师光鲜靓丽、从容潇洒的模样。可是,最近在法国出版的一本书却颠覆了我们...

飞鱼说编程
24分钟前
0
0
maven的pom.xml用解决版本问题

maven管理库依赖,有个好处就是连同库的依赖的全部jar文件一起下载,免去手工添加的麻烦,但同时也带来了同一个jar会被下载了不同版本的问题,好在pom的配置里面允许用<exclusion>来排除一些...

JAVA码猿
48分钟前
1
0
20180920 rzsz传输文件、用户和用户组相关配置文件与管理

利用rz、sz实现Linux与Windows互传文件 [root@centos01 ~]# yum install -y lrzsz # 安装工具sz test.txt # 弹出对话框,传递到选择的路径下rz # 回车后,会从对话框中选择对应的文件传递...

野雪球
今天
2
0
OSChina 周四乱弹 —— 毒蛇当辣条

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ 达尔文:分享花澤香菜/前野智昭/小野大輔/井上喜久子的单曲《ミッション! 健?康?第?イチ》 《ミッション! 健?康?第?イチ》- 花澤香菜/前野智...

小小编辑
今天
40
10

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部