初识插件化开发

最近要加入一个新的项目组,使用的技术都是之前没有接触过的,主要是利用Java的反射,动态加载技术,实现插件化开发。

目前要解决的问题是:实现框架与app之间的通讯。
所以特别的来了解一下插件化开发。

1.插件开发的介绍

1. 定义:

  所谓插件化,就是让我们的应用不必再像原来一样把所有的内容都放在一个apk中,可以把一些功能和逻辑单独抽出来放在插件apk中,然后主apk做到[按需调用],这样的好处是一来可以减少主apk的体积,让应用更轻便,二来可以做到热插拔,更加动态化。

2. 背景
image.png
3. 优点
image.png

2.插件开发需要解决的问题

1.类的动态加载

类的加载可以使用Java的ClassLoader机制,但是对于Android来说,并不是说类加载进来就可以用了,很多组件都是有“生命”的;因此对于这些有血有肉的类,必须给它们注入活力,也就是所谓的组件生命周期管理;

2. 资源的加载

资源加载方案大家使用的原理都差不多,都是用AssetManager的隐藏方法addAssetPath。

3.插件开发需要掌握的基础知识

  • ClassLoader类加载器

要想实现加载外部dex文件(即插件)来实现热部署,那么必然要把其中的class文件加载到内存中。

其中涉及到两种ClassLoader:DexClassLoader和PathClassLoader。而DexClassLoader可以加载外部的jar,dex等文件,正是我们需要的。

关于ClassLoader详解,见ClassLoader完全解析

  • Java 反射

因为插件apk与宿主apk不在一个apk内,那么一些类的访问必然要通过反射进行获取。所以了解反射对插件化的学习是必须的。

关于Java反射,见Java反射详解

  • 插件资源访问

res里的每一个资源都会在R.java里生成一个对应的Integer类型的id,APP启动时会先把R.java注册到当前的上下文环境,我们在代码里以R文件的方式使用资源时正是通过使用这些id访问res资源,然而插件的R.java并没有注册到当前的上下文环境,所以插件的res资源也就无法通过id使用了。

查看源码,通过“addAssetPath”方法重新生成一个新的Resource对象来保存插件中的资源,避免冲突。

关于插件资源访问,见使用插件中的R资源

  • 代理模式

插件化实现的过程主要靠欺上瞒下,坑蒙拐骗来实现。想想虽然加载进来了Activity等组件,但也仅仅是最为一个对象而存在,并没有在AndroidManifest中注册,没有生命周期的回调,并不能实现我们想要的效果。因此无论是dynamic_load_apk通过代理activity来操控插件activity的方式,还是DroidPlugin通过hook activity启动过程来启动插件activity的方式,都是对代理模式的应用。

关于代理模式,见静态代理与动态代理

至此,通过ClassLoader加载,然后通过代理模式让Activity等组件具有生命周期实现真正的功能,并且解决了资源访问问题。可能插件化已经可以简单的实现一些初步的功能,然而插件化绝不止于此。更多的内容仍需要进一步探索,不过以上知识是基础中的基础,必备之必备。

比较重要的两个插件开发框架介绍,它们的实现原理不一样
1. Dynamic_Load_apk (任玉刚)

Dynamic-Load-Apk简称DL这个开源框架,他的实现方式是,在宿主中埋一个代理Activity,更改ClassLoader后找到加载插件中的Activity,使用宿主中的Activity作为代理,回调给插件中Activity所以对应的生命周期。

这个思路与AndroidDynamicLoader有点像,都是做一个代理,只不过Dynamic-load-apk加载的插件中的Activity。

项目地址:https://github.com/singwhatiwanna/dynamic-load-apk

Dynamic-load-apk详解

2. DroidPlugin (张勇)

DroidPlugin它的原理是Hook客户端一侧的系统Api。
项目地址:https://github.com/DroidPluginTeam/DroidPlugin

DroidPlugin详解

4.插件开发的分类

插件式编程,由易到难,分以下个类型来说吧:

  • 简单的单向接口插件构架。
  • 双向式接口插件构架。
  • 界面式软件的插件构架。
  • 进程式插件构架

1.单向接口插件构架

框架不向插件开放任何接口,框架决定了怎么加载插件,怎么调用插件,怎么卸载插件,插件完全是被动的,只能干自己的活,不能反过来要求框架。

也就是说,框架老大,我说怎么干就怎么干。这种一般用于算法式的框架,比如提供加密算法框架,主程序不做具体的加密,由插件来完成加密,每完成一种合适的加密算法,就加入到插件目录,主程序中就可以多出一种加密算法选择,具体选择哪个,由用户来选择。

2. 双向式接口插件构架

单向式插件构架是最简单的一种,插件处于模块化的地位,没有任何的话语权,一般的介绍插件机制的文章,讲的都是这种,比较容易说清楚,但这种情况在真实项目中,一般是很少存在的,充其量是个模块化编程,根本算不上插件式构架。

框架调用插件的功能,天经地义,插件反过来调用框架,也是天经地义的。双方只有交互的情况下,才能更智能,更符合用户习惯,这才能算是一个标准的插件式构架。

交互就是一个互相调用的过程而已,因此,实现过程也不难,主框架也提供几个头文件,定义好一些接口,插件在运行过程中,可以调用主框架的功能,实现一些环境变量的获取与交互等功能。在实际项目中,插件和框架的头文件通常都放在一个目录即可,双方各负责实现自己定义好的头文件。这点在前面的例子中,已经演示过了,这里说说运行过程中的加载过程。

3. 界面式软件的插件构架

这个分类和前面说的构架,是一样的,唯独不一样的地方在于,界面。我们现在的客户端软件,如果不提供一个好看的,易用的界面,基本上很难扩大使用人群,而这点也制约了个人共享软件的发展,现在很难再出现以前那样有影响力的个人版本共享软件了,精力有限。

一个桌面软件框架,肯定有一部分的界面,需要插件来提供,比如提供工具栏,菜单,主客户端区域等等,而主框架也需要开放很多接口,供插件操作各种界面元素。这涉及到了大量的界面交互内容,这么一来,整个框架的复杂度将会提高很多,而框架的接口定义,也将增加很多,导致整个接口阅读和理解的难度增加。

在界面框架这块,事先的预定义很重要,要根据项目的内容进行规划,比如Word这样的,一个或者多个文档,各个插件都可以操作这个文档,还不需要提供客户区窗口。还比如winamp那样的,各个插件互相不干扰,也不使用主界面,都提供自己的界面,还比如QQ界面那样的,多个tab页,每个tab页面算一个插件,点击不同的tab按钮,出来自己的界面。这个界面需求定下来,接口设计也就不一样了。因此,构架需要按照你的界面要求而开发。

4. 进程式界面插件构架

最典型的例子,就是早期的某些浏览器,具备多tab页面功能,但如果某个页面卡死,整个浏览器都将无法使用,导致其他已经打开的网页也无法查看了。这促使后来的浏览器全部采用了多进程方式,也就是说,每个tab页面,实际上都是一个新的进程,某一个进程卡死,将不会对其他进程产生影响。

进程式插件构架实际上只是把多个窗口叠加在一起,看起来像一个程序,底层则是各走各的路,互不干扰。最基本的原理,就是基于WINDOWS的窗口HWND可以互相嵌套的原理。

Windows上面的各个进程,进程空间都是互不干扰,本进程要访问其他进程的东西,并在它的进程中加入自己的代码,都需要非常麻烦或者说高深的技术,但有一样除外,窗口。只需要使用FindWindow,就可以找到其他进程的窗口,窗口时windows的资源,所有的进程公用这些资源,当窗口所有资源耗尽的时候,就再也创建不了新的窗口了。这个限制,我得观察是6万多个,不知道对不对。自己的窗口在创建的时候,需要传入一个父窗口句柄,而这个父窗口句柄,是没有进程限制的。

进程式插件在解决了窗口问题之后,另外面临的问题,就是通讯问题,原来的接口指针,直接调用即可,现在这些指针,全部不能使用了。这里,我们可以采用如下图所示方案。

  • 主框架接口
  • 通讯模块
  • 加封/解封装模块
  • 插件模块接口
  • 加封/解封模块
  • 通讯模块

如果把上面的通讯模块,换成http通讯,把加封/解封换成xml封装方式,是不是和“soap”协议一模一样了?没错,标准的SOAP协议就是这么做的。我们可以不用HTTP,简单的TCP或者管道通讯即可,把接口用xml方式封装,然后传递到对端,即可形成插件调用机制。

作为构架,主要是把接口开放给插件,但要屏蔽掉进程通讯相关的细节,因此把以上的通讯机制,封装成一个lib或者dll,在插件中,调用这些函数的时候,通过通讯,会调用到主框架程序中。只要这个封装库做的够好,插件几乎完全不知道自己是进程式插件,还是单进程式插件。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容