范例解析:学习Phonegap的Plugin主板模式
1. 简介Phonegap的主板模式
HTML5/PhoneGap是由第三方公司所开发的框架,其内部采用主板模式来整合(组合)了HTML5、WebView和众多的Java插件(Plugin)。此主板模式嵌入于Android的UI框架哩,跟WebView搭配得非常的紧密,来共同支持HTML5。也就是支持Web App的开发及执行。由于Phonegap也是开源开放的软件,其主板模式的设计和应用,可成为我们的学习范例。
首先,其主板模式提供了IPlugin通用性接口,其Java代码如下:
// PhoneGap的IPlugin通用性接口定义
//------------------------------------------------------
package com.phonegap.api;
import org.json.JSONArray;
import android.content.Intent;
import android.webkit.WebView;
PluginResult execute(String action, JSONArray args, String callbackId);
void setContext(PhonegapActivity ctx);
public boolean isSynch(String action);
void setView(WebView webView);
void onPause(boolean multitasking);
void onResume(boolean multitasking);
void onNewIntent(Intent intent);
void onDestroy();
void onActivityResult(int requestCode, int resultCode, Intent intent);
boolean onOverrideUrlLoading(String url);
}
// End
这个接口定义了许多个函数,其中最主要的就是execute()通用性函数了。如下图:
Phonegap定义一个Plugin父类来实现<通用性>的IPlugin接口。如下图:
然后,以Java来撰写这个实现类,其Java代码如下:
// Phonegap的源代码
// Plugin.java
// -------------------------------------------------------------
package com.phonegap.api;
import org.json.JSONArray;
import org.json.JSONObject;
import android.content.Intent;
import android.webkit.WebView;
public abstract class Plugin implements IPlugin {
public String id;
public WebView webView; // WebView object
public PhonegapActivity ctx; // PhonegapActivity object
public abstract PluginResult execute(String action, JSONArray args, String callbackId);
public boolean isSynch(String action) { return false; }
public void setContext(PhonegapActivity ctx) { this.ctx = ctx; }
public void setView(WebView webView) {
this.webView = webView;
}
public void onPause(boolean multitasking) {}
public void onResume(boolean multitasking) {}
public void onNewIntent(Intent intent) {}
public void onDestroy() {}
public void onActivityResult(int requestCode, int resultCode, Intent intent) {}
public boolean onOverrideUrlLoading(String url) { return false; }
public void sendJavascript(String statement) {
this.ctx.sendJavascript(statement);
}
public void success(PluginResult pluginResult, String callbackId) {
this.ctx.sendJavascript(pluginResult.toSuccessCallbackString(callbackId));
}
public void success(JSONObject message, String callbackId) {
this.ctx.sendJavascript(new PluginResult(PluginResult.Status.OK,
message).toSuccessCallbackString(callbackId));
}
public void success(String message, String callbackId) {
this.ctx.sendJavascript(new PluginResult(PluginResult.Status.OK,
message).toSuccessCallbackString(callbackId));
}
public void error(PluginResult pluginResult, String callbackId) {
this.ctx.sendJavascript(pluginResult.toErrorCallbackString(callbackId));
}
public void error(JSONObject message, String callbackId) {
this.ctx.sendJavascript(new PluginResult(PluginResult.Status.ERROR,
message).toErrorCallbackString(callbackId));
}
public void error(String message, String callbackId) {
this.ctx.sendJavascript(new PluginResult(PluginResult.Status.ERROR,
message).toErrorCallbackString(callbackId));
}}
// End
于是,这个抽象父类担任两项任务:
- 实现了IPlugin接口,这是提供给众多Client来使用的外部接口。我们以”CI”(Interface for Client)来表示之。
- 定义了抽象函数,如上图里的execute()函数,成为提供给众多子类别来实现的内部接口。我们以<I>来表示之。
如下图:
这是简化型(或称退化型)的主板模式。此图里的Plugin抽象父类和两个接口,整合起来成为一个典型的软件主板。如下图:
这个Plugin软件主板是用来整合(组合)了HTML5、WebView和众多的Java插件(Plugin),所以我们称之为:Phonegap的Plugin软件主板。如下图:
2.简介Phonegap的主板模式
基于这个主板,我们就能开始进行组合了。此时,可设计一个子类,并且装配到主板的<I>接口上。如下图:
由子类来实现内部接口<I>。基于PhoneGap的框架,就可以写HTML5/JS模块来调用Java插件(即上图里的myPlugin子类)。在App执行时,用户会使用WebView画面而触发UI事件,JS就负责处理这些事件。必要时,JS会透过WebView(包含幕后的WebKit引擎)调用到IPlugin通用性接口的函数,转而调用Java插件里的execute()函数。如下图:
由于IPlugin接口只提供单一函数:execute();使得PhoneGap也只能提供单一函数:exec()。
3.通用性接口与Proxy-Stub设计模式
然而,在HTML5_JS里可能有多个函数,例如play()和stop()等。于是,在HTML5_JS里,必须从play()函数转而调用PhoneGap.exec()函数。这个PhoneGap.exec()再透过WebView而呼叫到IPlugin.execute()。如果我们在上述架构里面,加上一个myProxy类别,它包装了PhoneGap.exec()函数,扮演Java Plugin的Proxy(代理者)角色,如下图所示:
此时,HTML5_JS里面就看不到PhoneGap.exec()函数了,其好处是:
• 一方面让HTML5_JS程序代码比较单纯;
• 另一方面,让HTML5_JS与PhoneGap.exec()两者相依性(Dependency)降低,让HTML5_JS不受制于PhoneGap的框架界面。也因而提升了PhoneGap框架接口的变动自由度。
通常,在框架设计里,myProxy和myStub会是成对的,这称为Proxy-Stub模式。如下图所示:
于此,你已经观摩了如何使用proxy-stub模式来封装PhoneGap.exec()界面。◆
~ End ~