Android和Docker的一致架构设计(5)
-- <HTML5 + Docker>的插件集装箱
By 高焕堂 (台灣Docker論壇 主席)
2015/03/16 misoo.tw@qq.com
ee ee
高煥堂的相關文章:
A01、从「集装箱」思考Docker风潮:Docker潮流下的赢家策略
A02、Docker:从容<器>到集装箱设计之<道>
B01、Android和Docker的一致架构设计(1):追求今天决策的未来性
B02、Android和Docker的一致架构设计(2):包装<跨集装箱>的通信协议
B03、Android和Docker的一致架构设计(3):建立企业主的<核心集装箱>
B04、Android和Docker的一致架构设计(4):<分合自如>的设计模式
大家都知道,PhoneGap是基于HTML,CSS和JavaScript的跨平台移动App软件框架。例如,它能搭配HTML5来支持Web App的开发,并可发挥本地(Native)设备的功能,包括地理定位、加速器、联系人、声音和振动等。此外,PhoneGap还可以有效管理各种插件(Plugin),提供给HTML5应用来调用。于是,本文从HTML5跨平台的视角来看Docker、Android与PhoneGap的整合架构设计。让架构师扩大视野,涵盖终端和云平台,以一致的架构设计思维,追求决策未来性,开创产品的不一样生命。
例如,一般的语言表达Android的WebView的一段JavaScript语言:
// show.html (JavaScript程序代码)
<input type="button" value="Say hello" onClick="jsShow('Hello Android!')" />
<script type="text/javascript">
function jsShow(str) {
IToast.showToast(str);
}
</script>
当WebView(含幕后的Webkit里的其它类别)解析(执行)到其指令:
IToast.showToast(str);
就会去呼叫一段扩充的(Extended)的Java程序码(或称类别):
// myToast.java (Java程序代码)
public class myToast{
Context mContext;
myToast(Context c) {
mContext = c;
}
public void showToast(String str) {
Toast.makeText(mContext, toast, Toast.LENGTH_SHORT).show();
}
}
于是,上面的JavaScript程序代码就透过WebView而呼叫到这个showToast()函数了。那么,这两段程序代码之间,又由谁来建立其连结关系呢? 那就依赖另一段程序代码了,就是:
// myActivity.java
public class myActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView appView = new WebView(this);
appView.loadUrl("file:///android_asset/www/index.html");
appView.getSettings().setJavaScriptEnabled(true);
myToast obj = new myToast();
appView.addJavascriptInterface(obj, "IToast");
appView.loadUrl("file:///android_asset/show.html");
setContentView(appView);
}
其中的指令:
myToast obj = new myToast();
就诞生一个myToast类别的对象。接着,
appView.addJavascriptInterface(obj, "IToast");
就将该对象的参考(Reference)传递给WebView,这建立了WebView与myToast类别(对象)之间的链接关系。让WebView在执行JavaScript程序代码时,可以来呼叫myToast类别里的showToast()函数。首先,以图形表达出来:WebView与Android框架的关系:
图-12、 WebView是Android框架的一部分
然后,以图形来表达JavaScript程序代码(即show.html)和myToast类别,如下图:
再以图形来表达myActivity类别,如下图:
图-14、 myActivity继承Activity基类
由myActivity类别来诞生WebView对象,也诞生myToast对象,如下图:
接着,由myActivity呼叫WebView的addJavascriptInterface()函数,将myToast对象的参考(Reference)传递给WebView对象,这建立了WebView与myToast类别(对象)之间的链接关系。如下图:
接着,由myActivity呼叫WebView的loadURL()函数去将show.html载入到WebView里,如下图:
建立了链接关系之后,JavaScript的jsShow()函数就能透过WebView而呼叫到myToast的showToast()函数了,如下图:
从图里可以看出来,JavaScript模块(即jsShow()函数)与Java模块(即myToast类别)之间的相依性(Dependency)非常高,也就俗称的<高耦合性>,所以很不利于JavaScript模块的跨平台,也连带导致HTML5代码的框平台要求。因而有了PhoneGap框架来化解上述的不利情形。搭配PhoneGap的新架构就如下图所示:
由于IPlugin接口只提供单一函数:execute();使得PhoneGap也只能提供单一函数:exec()。然而,在HTML5_JS里可能有多个函数,例如play()和stop()等。于是,在HTML5_JS里,必须从play()和stop()函数转而呼叫PhoneGap.exec(),然后透过WebView而调用IPlugin接口的execute()函数;最后转而调用myPlugin的mpPlay()和mpStop()函数。其中的接口转换过程,以程序代码表达如下:
var myProxy=function(){};
myProxy.prototype.play = function(success, fail, para1, para2){
return PhoneGap.exec( success, fail,
'myPlugin', //java类别名称,注册于plugins.xml中
'mpPlay', //在Plugin里用来配对的action名称
[para1, para2] //所传递的参数(parameter),Array结构
);
};
myProxy.prototype.stop = function(success, fail, para1, para2){
return PhoneGap.exec( success, fail,
'myPlugin', //java类别名称,注册于plugins.xml中
'mpStop', //在Plugin里用来配对的action名称
[para1, para2] //所传递的参数(parameter),Array结构
);
};
PhoneGap.addConstructor(function() {
PhoneGap.addPlugin('myProxy', new myProxy());
});
此时,HTML5_JS里面就看不到PhoneGap.exec()函数了,其好处是:一方面让HTML5_JS程序代码比较单纯;另一方面,让HTML5_JS与PhoneGap.exec()两者相依性(Dependency)降低,让HTML5_JS不受制于PhoneGap的框架API。因而HTML5实现了完美的跨平台特性。
4、结语
人们不会期待一辆完整汽车既能在沙滩上跑,也能街道、高山、雪地里跑。