使用FireBreath写浏览器插件(二)

二. Firebreath的实际应用

    去年我在给公司开发PC上Widget引擎,这个Widget引擎上面运行WebApp应用,界面和应用逻辑使用HTML+CSS+Javascript实现,而网页无法实现的功能则由CAR实现(CAR是与COM类似的技术,不过支持反射和AOP编程)。在这个引擎上开发的第一款应用是:类似于91手机助手的Android PC套件,整个PC套件的UI部分全部用HTML+CSS+Javascript实现,没有使用任何原生的控件(例如button),而JS无法完成的功能(例如获取联系人,安装apk包)则由CAR实现,然后在js中调用CAR。


    其实扩展js功能,还有一种方法是使用现在网站常用的web service:在程序中实现一个http server,然后在http server中实现JS无法完成的功能,例如PC套件里面的获取联系人,最后再使用Ajax去调用。但为什么不选用这种方法呢?主要是基于如下几点原因:

1. 管理同步调用非常麻烦

2. js得处理参数转换

3. webservice除了本进程可以调用外,其他应用可以调用,安全认证比较麻烦

4. http无状态,长时间执行的操作得用一些特殊方式处理

5.  保持长连接也挺麻烦,回调机制的实现比较难办

6.  对象的生命周期管理难以与js的垃圾回收同步

7.  与本地UI交互困难。例如由于网页只能打开特定的对话框,如果应用要打开特定对话框(例如选取文件夹),webservice实现比较麻烦 。

    在我看来,C++里面的对象对JS而言,就应该和JS里面的原生对象(例如Date)是一样的,可以new对象,可以和原来一样地调用C++对象里面的方法,可以注册事件和触发事件,可以被垃圾回收。基于这个原则,并利用CAR的反射和事件回调机制,可以将CAR实现C++类动态注入到JS引擎中,使得JS可以轻松地调用C++对象。举个例子:

    先写一个接口描述文件HelloWorld.car:

module
{
    interface IHelloRef {
        test([in] Int32 n, [out] AStringBuf<32> ret);
   }
    //回调函数
    callbacks JHelloRef {
        onTestCallback();
    }

    class CHelloRef {
        interface IHelloRef;
        constructor([in] Int32 abc);
    }
}


    然后用emake编译HelloWorld.car可以生成相关的.h和.cpp文件,修改cpp文件为如下:

#include "CHelloRef.h"
#include "_CHelloRef.cpp"
#include <stdio.h>
#include <windows.h>
ECode CHelloRef::test(
    /* [in] */ Int32 n,  * [out] */AStringBuf* ret)
{
    printf("hello world\n");
    //触发回调
    Callback::onTestCallback();
    ret->Copy("hello world");
    ret->Append(n);
    //睡眠3秒后返回结果
    ::Sleep(3000);
    return NOERROR;
}
ECode CHelloRef::constructor(Int32 abc)
{
    return NOERROR;
}


    在js中可以这么调用:

var hello = new HelloWorld.CHelloRef(1234);
hello.onTestCallback = function(){
       window.alert('onTestCallback ’);
};
//调用test将触发onTestCallback,test的执行将耗时3秒以上,js引擎也会“卡死”3秒以上
var ret= hello.test(11);
//ret等于hello world11
alert(ret);
//异步调用,下面的js代码可以继续执行,而不至于js引擎卡死,结果返回时调用function
hello.test(32, function(ec, ret){
    //ret等于hello world32
    alert(ret);
});


    最初我是采用在Webkit外壳上注入CAR的方式,但后面想在IE内核上跑应用时发现还得实现一遍注入,因为浏览器之间用的JS引擎接口不一样。即使是Webkit,也有多个JS引擎,例如V8和SquirrelFish,我不可能每个js引擎都实现一遍。但浏览器主要由两种插件体系:NPAPI(chrome里面加入了Pepper Plugin API )和ActiveX,一个体系下插件的接口是一致的,因此使用插件方式只需要编写两种方式的注入,有了Firebreath之后更简单,只需要实现一致方式的注入就可以在各个浏览器上跑了。下面是在chrome里面跑pc套件的截图:

使用FireBreath写浏览器插件(二)_第1张图片

    图上的url(http://moyang.org/pcwidget/widgets/application/com.kortide.app.pcSuite/jdy.html )里面运行的是一个测试版,还有一些缺点(例如图片没有按需加载,第一次使用需要等待图片加载完)。IE里面排版还有点问题(万恶的CSS浏览器兼容),推荐在chrome或firefox里面运行。有android手机的可以试试,好久没弄这个了,跑不起来我可不负责^_^。

    虽然插件是一种比较方便的方式,但在手机上通过插件来扩展并不是一种好的方式,而且插件在效率上确实有点损耗,所以应该尽量在浏览器外壳或js引擎里面注入,这样Webapp运行起来才有好的用户体验。插件将各个js引擎的API进行了统一,有优点也有缺点,属于一种穷人的解决方案。

好了,闲话讲完了,后面将接着介绍如何通过Firebreath写插件。

你可能感兴趣的:(浏览器,webservice,chrome,Constructor,webapp,js引擎)