OPhone架构剖析—Widget部分

OPhone平台开发, 2009-12-07 17:12:01

Tags : Widget JIL规范 Ophone平台

概述
       中国移动对OPhone平台了做了深度定制,平台接口和应用更贴合中国用户的需求。其中,OPhone对Widget JIL规范的支持,是该平台一大亮点,让开发者有能力创造更丰富的应用。
 

为什么Widget开始流行
        如今,软件巨头为什么这么热捧Widget?我们在这儿做一点浅显的探讨:Widget,不单单是把网页从PC浏览器搬到手机应用里那么简单,因为它包括HTML、CSS、JavaScript、Flash、服务端技术和未来的HTML5,是一套发展多年的成熟技术。
 

        如下图:


       我们可以看到建立在Internet上庞杂的万维网体系结构,而且还在不断发展中,比如最近的云计算风暴,HTML5,富客户端等等,这是新一波的技术革命,而Widget是打头阵的。
 

       其次,Widget可以更直接的展现应用内容,使用户不需要在URL间跳来跳去找感兴趣的内容。
 

       再次,Widget的尺寸很小,这让它下载的更快,更节省流量;又因为是网络应用,还具备更新更及时和互动性更强的特点。
 

对浏览器进行扩展
        这里,我们抛开规范细节不谈,粗略的来理解:OPhone JIL标准的Widget是为JavaScript提供了一套API。遗憾的是:笔者无缘看到OPhone源码,本文的目的是猜测这套API是如何得到支持的。
我们知道OPhone平台的浏览器基于WebKit,如何为一个浏览器做扩展我们可以想到以下几种方式:

  •  插件
  •  直接为JavaScript Core引擎做扩展
  •  类似JQuery等JavaScript库的支持方式   
  •  用Java做扩展

       我们来详细分析一下这几种方式:

        (1). 插件
        此处的插件是指NPAPI,因为Android WebKit只支持这种方式,请区别于FireFox的扩展和Apple开发的WebKit-based plug-in方式(用Object-C开发)。
 

        NPAPI(Netscape Plugin Application Programming Interface)是一套古老而经典的接口,是Netscape留给我们的宝贵财富。浏览器对Flash和PDF的支持,都是通过这套接口实现的。这套接口可以不修改浏览器代码,就能扩展浏览器的功能。比如Flash,用户可以选择装或者不装;而Flash开发商(Adobe),可以升级插件库本身,而不必让用户升级浏览器,就能支持高版本的Flash。 所以说,NPNPI是一套灵活有效的机制;现在,主流浏览器都支持它(如,IE, FireFox, WebKit, Chrome, Opera)。
详细的开发指导,请访问:https://developer.mozilla.org/en/Gecko_Plugin_API_Reference
 

         (2). 直接为JavaScript引擎做扩展
         如对DOM中定义的window对象的支持通过这种方式实现。这中方式,各家浏览器只要保证支持规范中定义的对象和接口就可以了,所以具体实现是不同的。
 

        要了解这方面内容,大家只能去读代码了,比如WebKit源码目录:WebCore/dom/模块。
 

       (3). JavaScript库
       JQuery, YUI, Spry,这些库不仅使用简便,还提供了一致的功能(因各浏览器实现的差异或bug导致同样代码的表现不同)。如下方式引用JQuery:
 

<script type="text/javascript" src="jquery.js"></script>

       (4). 用Java做扩展
       这种方式是Android WebKit独有的方式,是本文重点介绍的内容。
   

       Qt平台的WebKit组件大量使用Qt扩展Web功能,这与Android WebKit用Java扩展使

       用了同样的机制,只是实现功能时一个用C++,一个用Java。
 

       这方面了解:
 

Qt Jambi: http://doc.trolltech.com/qtjambi-4.5.2_01/com/trolltech/qt/qtjambi-index.html
Qt Scriping: http://doc.trolltech.com/4.6/scripting.html
源码:WebCore/bridge/qt模块
 

总结
        (1),(2)的优点是运行效率高,但实现较复杂,特别是直接为JavaScript Core引擎扩展的方式,不利于合并,因为Android是个开源项目,不断升级、完善是开源项目的特点,我们当然不想因每次升级,频繁对我们的扩展做适应性修改。
        (3),(4)非常简便。我们如果把这两种方式结合起来使用:Java做基础架构,JavaScript抹平与Java语言间的差异,使两者做到无缝衔接;因为JavaScript中有匿名对象和匿名函数的概念,这些对象传给Java前要做一些转换工作;而且对于那些与平台无关的JavaScript代码,我们可以在PC的FireFox环境中调试。
最近,笔者还看到一个Titanium项目,该项目可以让开发者用Ruby/Python/PHP/Lua等语言协同JavaScript做开发,并且支持语言间互相调用。
 

        Titanium介绍:http://www.linuxjournal.com/article/10437

         好了,介绍了这么多,让我们开始Hack OPhone吧。
 

        我们把如下接口作为扩展,加入WebKit:
DD.Extend.trace();
该接口的作用是调用以下方法,在终端打印调试信息:
android.util.Log.i(“JavaScriptExtend”, msg);
首先让我们熟悉一个方法:
android.webkit.WebView.addJavascriptInterface(Object obj, String interfaceName);
 该方法把一个Java对象绑定到JavaScript运行时空间,第二个参数的含义为:在JavaScript空间中访问该Java对象所使用的名字。
 

        (1).  利用addJavascriptInterface向JavaScript运行时空间添加对象
main.xml
 

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>

<WebView
android:id="@+id/webview"
android:layout_width="fill_parent" 
android:layout_height="0dip"
android:layout_weight="1"
/>
</LinearLayout>


 

index.html

 

<html>

<head>
<title>TestCase</title>
<script>
function callMe() {
window.Extend.trace("Hello,world");
}
</script>
</head>

<body>
<div onclick="javascript:callMe();">Click Me</div>
</body>
</html>

WebViewDemo.java

 

package com.google.android.webviewdemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebSettings;
import android.webkit.WebView;

public class WebViewDemo extends Activity {

private WebView mWebView;
private Trace jsInterface;
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);

mWebView = (WebView) findViewById(R.id.webview);

WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setAllowFileAccess(true);
webSettings.setCacheMode(android.webkit.WebSettings.LOAD_NO_CACHE);

jsInterface = new Trace();
mWebView.addJavascriptInterface(jsInterface, "Extend");
mWebView.loadUrl("http://192.168.153.1/index.html");
}

public class Trace {
public void trace(String msg) {
Log.i("JavaScriptExtend", msg);
}
}

}


解释:
       WebSettings.setJavaScriptEnabled(true)激活JavaScript引擎;创建Trace对象,并把它加入JavaScript执行空间,命名为”Extend”;最后,装载网页。
       注意一点:WebSettings.setCacheMode(android.webkit.WebSettings.LOAD_NO_CACHE)关闭Cache有利于我们调试。
 

         (2). 善用JavaScript
JavaScript与Java间有一些差异性,比如匿名对象:

var someObj = {
property:"Level one",
propertyB:{
property:”Level two”
}
}

     someObj是JavaScript中的一个匿名对象,我们没办法把该对象直接传给Java。
此外,我们还要解决命名空间的问题,比如DD.Extend.trace()。
为了解决上面的两个问题 ,我们来实现一个简单的JavaScript库:JSLib.js。
 

JSLib.js

var DD;

if(!DD) DD = {};
if( !DD.Extend) DD.Extend = {};

DD.Extend.trace = function(msg) {
var str = JSON.stringify(msg);
window.Extend.trace(str); 
}

      我们的JSLib非常简单,首先创建了命名空间,接下来把传给DD.Extend.trace的参数用JSON库转化,最后把结果传给Java处理。利用JavaScript很简单的解决了JavaScript与Java混合编程碰到的命名空间和JavaScript对象传递的难题。
 

       我们此时能深刻体会到:语言没有优劣之分,只要能选择恰当,就能给我们的工作带来巨大的便利。
JSON 是一种轻量级的数据交换格式,更详细的信息,请到http://www.JSON.org/js.html
 

改进的index.html

<html>
<head>
<script type="text/javascript" src="./JSLib.js"></script>
<script type="text/javascript" src="./json.js"></script>
<title>TestCase</title>

<script>
function callMe() {
DD.Extend.trace("Hello, world");
DD.Extend.trace({
property  :"Level One", 
propertyA : {
A:"A",
B:"B"
}
});
}
</script>
</head>

<body>
<div onclick="javascript:callMe();">Click Me</div>
</body>
</html>

       通过上面的例子,我们成功的为WebKit做了扩展。很简单吧?不过它看起来技术含量不够高,我们可以做到不让用户显示的引用JSLib.js库,而是在装载网页之前,后台改写,偷偷加上对JSLib.js库的引用。
值得一提的是:android.webkit.*包内,有大量功能值得我们探索。
 
总结
       巨头正出台大量的Widget规范,比如W3C Widget、NFB Widget、BONDI和JIL,这些规范降低了嵌入式平台的编程门槛,虽然写一个好应用从来不是一个简单的事(语言和工具没法解决编程复杂性问题),但有了好用的工具,我们能更快建模,验证想法,从这方面来看也是有巨大价值的,感谢平台提供商做的努力。
 

        小文一篇,希望对大家有帮助。

作者介绍
        窦川,软件工程师,从事JavaVM的移植和研究工作。
  do.chuan@gmail.com

 

(声明:本网的新闻及文章版权均属OPhone SDN网站所有,如需转载请与我们编辑团队联系。任何媒体、网站或个人未经本网书面协议授权,不得进行任何形式的转载。已经取得本网协议授权的媒体、网站,在转载使用时请注明稿件来源。)