PhoneGap学习笔记四:PhoneGap底层原理(下)

来源:互联网 发布:专业屏幕录制软件 编辑:程序博客网 时间:2024/05/18 20:06

本篇主要讲解PhoneGap的两个重要的类,PluginManager类和CallbackServer类。

PluginManager类

PluginManager类实现了PhoneGap的插件管理机制,并在CordovaWebView提供出JavaScript接口。在CordovaChromeClient类的onJsPrompt()方法中截获JavaScript消息,根据消息具体执行某一个插件。代码如下,

String r = this.appView.pluginManager.exec(service, action, callbackId, message, async);

在上篇博客讲解CordovaWebView类时曾提到,PluginManager的实例化是在CordovaWebView的初始化init()函数调用setup()方法时执行的。

复制代码
1         //Start up the plugin manager2         try {3             this.pluginManager = new PluginManager(this, this.cordova);4         } catch (Exception e) {5             // TODO Auto-generated catch block6             e.printStackTrace();7         }
复制代码

我们首先看一下PluginManager类的构造函数:

View Code

传入参数有两个CordovaWebView类型的app和CordovaInterface类型的ctx。这两个参数比较重要,PluginManager是和CordovaWebView绑定的,要求必须是CordovaWebView类型,第二个参数必须是实现了CordovaInterface的Context。为什么是必须呢?这里留下一个悬念,如果你只做PhoneGap层的应用,可以不关心这个问题。初始化firstRun为true,这个Flag用来判断初始化时是否需要加载插件。

并在CordovaWebView的loadUrlIntoView()方法中进行了初始化工作。

this.pluginManager.init();

那在初始化中到底完成了哪些工作?看一下代码就很好理解了。

init

首先判断firstRun是否为true,如果为true,则执行this.loadPlugins()加载插件,并把firstRun置为false。否则停止plugin工作并销毁对象。

最后执行this.startupPlugins()启动插件。

下面我们来看看如何加载插件的。

loadPlugins

 PluginManager类加载插件是通过读取res/xml/plugins.xml文件实现的。首先取得xml文件id,然后通过id取得xml文件的内容。接下来是解析xml文件,每次都会读取出插件Plugin的service(如Camera、Notification等)、pluginClass(如org.apache.cordova.CameraLauncher、org.apache.cordova.Notification等)和onload(判断插件初始化时是否需要创建插件的flag)。最后通过addService将读取到的插件添加到PluginEntry的list中去。

在插件实体类PluginEntry中有一个属性onload可能让人有些迷惑,在plugins.xml中并没有关于onload的节点,也就是说在解析xml文件时

onload = "true".equals(xml.getAttributeValue(null, "onload"));

这里的onload是被赋值为false的。个人猜测是为以后的插件扩展预留的接口,在初始化时需要先创建这个插件。

在startupPlugins()函数中,主要是做了onload被设置成true时(目前还没有这种情况)的插件创建工作。

startupPlugins

 

好了,插件初始化完毕,万事具备只欠东风了。这里的“东风”是什么?当然是插件的执行了。

exec

本篇开始已经提到过,插件的执行是在CordovaChromeClient的onJsPrompt()方法中截获JavaScript消息,根据消息具体执行某一个插件来调用的。几个传入参数再说明一下

service:需要执行的某一项服务,如Camera、Notification、Battery等等;

action:服务执行的具体动作,如takePhone、getPicture等

callbackId:如果插件是异步执行的话,那么插件执行完成之后回调执行的JavaScript代码的Id存放在callbackId中(好长的定语⊙﹏⊙b汗)。

jsonArgs:即上篇提到过的message消息,存放着服务的调用信息。

async:布尔变量,标明JavaScript端是否需要执行回调。如果是true,则Cordova.callbackSuccess(...)或者Cordova.callbackError(...)需要被执行。

    实际这个值传入时默认都是true的,插件是否是异步执行是通过plugin.isSynch(action)来判断的。估计开始时想让开发者指定插件是否要异步执行,后来添加了plugin.isSynch()的方法来判断。

首先判断插件是否是异步执行,如果是ture的话,新起一个线程执行。

PluginResult cr = plugin.execute(action, args, callbackId);

通过PluginResult类型返回值cr的取得status和 cr.getKeepCallback()是否执行app.sendJavascript()方法。

如果插件不是异步执行,则直接调用cr = plugin.execute(action, args, callbackId)方法执行插件服务。

CallbackServer类

如果说前面所讲的几个类都是为后台JAVA端服务的话,那么CallbackServer类就是为前台JavaScript服务的了。

 下面我们看看CallbackServer类官方文档的解释:

CallbackServer 实现了 Runnable 接口,具体的功能就是维护一个数据的队列,并且建立一个服务器,用于 XHR 的数据传递,对数据的队列的维护利用的是 LinkedList<String>。

XHR处理流程:

1. JavaScript 发起一个异步的XHR 请求.

2. 服务器保持该链接打开直到有可用的数据。

3. 服务器把数据写入客户端并关闭链接。

4. 服务器立即开始监听下一个XHR请求。

5. 客户端接收到XHR回复,并处理该回复。

6. 客户端发送新的异步XHR 请求。


如果说手持设备设置了代理,那么XHR是不可用的,这时候需要使用Pollibng轮询模式。 
该使用哪种模式,可通过 CallbackServer.usePolling()获取。


Polling调用流程:

1.客户端调用CallbackServer.getJavascript()来获取要执行的Javascript 语句。
2. 如果有需要执行的JS语句,那么客户端就会执行它。
3. 客户端在循环中执行步骤1.

前面已经讲到过,在CordovaWebViewClient类的onPageStarted方法中实现了CallbackServer的实例化和初始化。

按照惯例,首先来看一下CallbalServer类的构造函数:

CallbackServer

构造函数比较简单,初始化的时候设置活动状态this.active = false;JavaScript队列为空this.empty = true;端口初始化为0 this.port = 0;新建一个LinkedList<String>类型的javascript队列。

然后再看一下初始化方法

init

CallbalServer类支持两种执行模式,一种是Polling,另为一种是XHR(xmlHttpRequest)。在初始化init方法中先判断使用哪种模式。如果是打开的本地文件或者设置设置了代理,则使用polling的模式,否则,使用XHR模式,并启动Server。

由于CallbalServer类实现的是 Runnable 接口,在 CallbackServer 中,最主要的方法就是 run() 方法,run() 方法的具体内容简介如下:

run

 

首先利用 ServerSocket 监听端口,具体端口则自由分配。
在 accept 后则是对 HTTP 协议的解析,和对应的返回 status code。
在验证正确后,利用 getJavascript 方法得到维护的 LinkedList<String>() 中的保存的 js 代码,如果为空则返回 null。
这些具体的 string 类型的 js 代码则利用 socket 作为 response 返回给前端。
之后就是对队列维护的方法,这时理解之前的 sendJavaScript 则很简单,该方法与 getJavaScript 相反,一个是从 LinkedList 中取出 js 代码,一个则是加入。
综上,CallbackServer 实现的是两个功能,一个是 XHR 的 SocketServer,一个是对队列的维护。

 

 

原创粉丝点击