Google Gears 指南
Gears概述
Google Gears 是一个开源的浏览器插件,它支持用户浏览器能够使用开发者创建的基于 Gears 的离线应用。它提出了一种离线应用的思想,它的三大核心模块将帮助开发者更好地运用这个思想来开发。Gears 技术是基于客户端语言 JavaScript 技术的扩展。
Google Gears提供一种浏览器存储支持技术,这种技术使得传统的WEB应用的浏览器层再不仅仅只具有页面的显示能力,而还将具备把远程数据同步到本地,并在本地对数据结构化利于访问和查询,最后还能把处理之后的数据在后台同步到服务器。其总体框架如下图:
Google Gears是作为一个浏览器的插件被安装在本机的,Gears 所支持的操作系统和浏览器包括 Windows, Windows Mobile, Mac (Firefox, Safari), Linux and Android。因此,Gears支持目前主流的操作系统和浏览器,具有极强的兼容性和广泛的适用范围。、
Gears具有如下特性:
- 能够让WEB应用程序可以更自然的与本地桌面应用交互
- 能够把数据以结构化的形式存储到本地数据库,方便查询
- 能够在后台运行JavaScript以提高执行效率
Gears 实际上提供了一种离线模型来设计应用程序,我们可以把这种模式理解为一种本地服务模式。事实上,Gears就是通过它的关键组件来缓存应用资源,并在离线状态下可用。因此,存储应用资源就是Gears的一个关键技术。
在传统的应用中,应用资源及数据都是被存储在服务器一端的,即使在客户端也是一些有限的非结构化的数据,比如Cookie等。然而,要是采用离线式的应用形式,数据就必须要存储到本地;而存储的数据为了能够方便的访问和查询,就必须要以结构化的数据存储。因此,提供一个本地的关系数据库是一种比较好的形式。当作业在离线完成之后,就需要使得本地的数据能够和服务器的数据进行同步;当然,这里有很多方案可供选择;因为,不同的系统结构可能不同的方案。另外,Gears的数据库提供了全文简述的方式,因此Gears能够在数据库文件中很快做文本查询。
Gears由于数据的处理有一部分是在客户端进行的,因此可能存在客户端处理大量的数据或是在同步的时候要同步大量的数据,那么执行性能可能会有所降低。不过,Gears提供了一种叫做WorkerPool的技术,使得这类操作可以在程序执行的后台进行操作,从而使得这种需要长期等待的作业不会影响用户的其他操作。
Gears的体系结构
在研究Gears的体现结构之间,我们先来看看一些常见的数据处理结构。
缺乏数据层的结构
典型的就是直接使用AJAX的远程调用,AJAX把服务器暴露出来的APIs理解为一个数据源,通常AJAX只用获取服务器的数据而不缓存数据。
具有一个数据层的结构
如果你的AJAX程序通过一个JSON访问Internet应用,当然你还可以通过中间对象来传递数据;你可以通过该对象判断数据是来自服务端、客户端存储的或两者的协作数据。使用中间对象可以传递到服务器,也可以接受服务器的数据到客户端,它还可以选择是否同步服务器和客户端的数据。这样做的好处是,客户端动过一个数据对象和服务器进行交互处理。但是,这存在一个问题,就是在数据层里不是很容易区分服务端的数据、客户端的数据或需要同步的数据。
提供数据选择器的结构
如果你在数据层之上增加一个数据选择器充当数据层的数据接口,那么你就可以通过选择器区分那些数据层的数据来自服务器,那些来自客户端,那些要同步。显然,这样做解决了上述区分数据的问题。但是,在客户端的数据都只能是暂时存储的,要是结束应用就必须要把长期存储的数据同步到服务器上去。
通过本地存储的结构
那么接下来,我们要是在本地增加一个数据层并提供一个本地的数据库,那么我们的数据层就会有两个,一个来自服务器,另一个则来自本地。这样做,你可以把离线数据存储到本地库,并通过与服务器交互的数据层进行同步。
通过上述四种结构的演绎,我们的目的是要使得离线模型的应用程序成为可能。当然,并不是任何应用都需要采用离线模型,这一切都要取决与应用的逻辑和连接策略。比如,你的数据是实时更新的,就好像股票的信息你可能在客户端只需要知道当前的实事数据那么就不需要离线作业,再比如,一些在线聊天系统的消息等,这些都不需要离线模型来进行处理。
总的来说,应用访问本地数据的性能肯定要比每次都使用来自服务端的数据要高。但必须要考虑程序的代价和收益,因为本地离线数据也是要与服务器同步的。
后台同步结构
如上图通过一个同步引擎在后台同步本地和服务器之间的数据,这样做的好处很明显,客户在离线作业的时候不需要考虑应用的状态同步,而是通过一个后台引擎同步。而Gears的结构就是这样一种结构。
Gears的安全性
Gears提供的最基本的安全机制是,通过对一个域(及端口)提供一个数据库和一个服务。另外,当用户访问某个Internet应用的时候,插件会提示用户是否启用Gears。同时,在浏览器终端Gears也会通过客户在操作系统登录的用户以确保终端文件的安全性;因此,在同一个操作系统上两个不同的用户访问的也是不同的Gears文件。最后,为了防止SQL的注入攻击,Gears还提供了(?)输入参数化来防止攻击,以提高安全性。
例如,我们通常推荐这样db.execute('insert into MyTable values (?)', data);而不同推荐这样db.execute('insert into MyTable values (' + data + ')');。
Gears功能预览
- l 本地数据库
- l 访问文件的能力
- l 本地化
- l 与本地桌面交互
- l 后台处理
后面我们将通过一个专题一个例子的方式来介绍Gears的这些功能,并讨论这些功能的应用范围。
要使用Gears就必须去先安装Gears插件到浏览器,并在页面中引入gears_init.js文件,加载并初始化gears插件。
本地数据库
就如同我们在Gears的体现结构中谈到的那样,Gears提供了一个本地数据库,事实上这个本地数据库是一个SQLite数据库。该数据库的文件位置如果在Windows上就是在Windows的用户文件夹的目录下:
文件里有三个db文件,分别是geolocation.db、localserver.db和permissions.db文件,geolocation是国际化库,localserver是Gears服务库而permissions是Gears的MetaData数据库。我们的数据文件,是根据域来存放的。
我们已经大致了解了Gears的工作情况,在前面的Gears的体系结构中,我们也知道Gears提供了JavaScript的接口供用户在页面访问该数据库。操作Gears的数据库和通常下的数据库访问代码类似。大致步骤如下:
1. 创建连接到数据服务上
2. 打开服务上的某个数据库
3. 执行SQL指令(DDL和DML)
例如如下代码:
db = google.gears.factory.create('beta.database');
db.open('database-personInfo');
db.execute('SQL Command');
另外,如果在执行Select语句的时候可能会产生结果集,在结果集的处理上通过db.execute方法返回一个rs结果集,在结果集上可以通过isValidRow方法判断是否可以继续迭代,并通过next方法进行迭代。在结果集上,如果要取的所迭代的行上的数据可以通过field(index)方法,其中index参数表示行中列的索引。如下代码:
var rs = db.execute('select * from XXX ');
while (rs.isValidRow()) {
col0=rs.field(0)
rs.next();
}
基于代码封装的考虑,我们建议对上述代码进行包装,这里提供一种包装实现以方便以后的复用。
function GearsDB(databasename){
var _this=this;
var db=null;
_this.dbname='';
var isopen=false;
//构造函数
var init = function()
{
_this.dbname=databasename;
};
init();
//打开Gears的数据库连接
this.open=function(){
var result=true;
if (window.google && google.gears) {
try {
_this.db = google.gears.factory.create('beta.database');
if (_this.db) {
_this.db.open(_this.dbname);
_this.isopen=true;
}//end if;
} catch (ex) {
result=false;
}//end true;
}//end if;
return result;
}
//在Gears创建的数据库中建表
this.createTable=function(ddl){
if(_this.db && _this.isopen){
_this.db.execute(ddl);
}//end if;
}
//封装执行更新的SQL代码
this.executeUpdate=function(sql,params){
if(_this.db && _this.isopen){
_this.db.execute(sql,params);
}//end if;
}
//封装执行查询的SQL代码,查询通过rowmap回调函数完成对结果集数据赋值
this.executeQuery=function(sql,params,rowmap){
var resultlist=null;
if(_this.db && _this.isopen){
resultlist=new Array();
var rs=_this.db.execute(sql,params);
while (rs.isValidRow()) {
var col=rowmap(rs);
resultlist.push(col);
rs.next();
}//end while;
}//end if;
return resultlist;
}
//关闭Gears的数据库连接
this.close=function(){
if(this.db && this.isopen){
this.db.close();
}//end if;
}
}
访问本地文件及上传
访问本地文件实际上就是通过Gears与本地的桌面系统交互,Gears为此提供了一个Desktop的访问对象,该对象实际具备两个操作一个是访问桌面的问文件系统,另一个则是用来创建快捷图标到桌面。openFiles方法就是用来打开本地文件的,它可以通过一个系统提供的文件选择对话框对文件进行选择。该方法的原型为:void openFiles(callback, [options]),其中callback表示在选择文件后的回调函数(注:之后上传功能就在该函数中完成),options是选项类型OpenFileOptions。其中,回调函数的原型是OpenFilesCallback(File[] files),该函数中的files表示选择的文件数组。File是Gears提供的文件类型,其中有两个只读属性name和blob。name表示文件名,blob表示以二进制存储的文件内容。OpenFileOptions也是由Gears提供的数据类型,有两个配置属性singleFile和filter,singleFile是个boolean值,true为只选择一个文件,false表示可以选择多个;filter表示要过滤的文件类型。具体操作,如下例:
//用来创建desktop对象
var desktop = google.gears.factory.create('beta.desktop');
//调用openFiles方法,打开文件
desktop.openFiles(
function(files) {//回调函数
if(files.length==0) return;
var msg='';
for (var i = 0; i < files.length; i++) {
msg+=' '+files[i].name;
}
alert(msg);
},
{ singleFile:true,filter: ['text/plain', '.html'] }
);
上述功能,用来打开单个文件,默认只显示text和html文件,文件打开后显示刚才选择的文件名。
通过Gears我们可以选择并打开文件,那么要上传文件Gears又为我们提供了一个HttpRequest类,通过该类我们可以通过http协议把文件流传输到服务器上。该类实际上是W3C的XMLHttpRequest的特定实现,之所以如此是因为Gears的HttpRequest类能够更好的运作在Gears的后台处理中,它除了具备XMLHttpRequest的功能意外,关键是能够和Gears更好的协同作业。要使用HttpRequest对象首先要先创建该对象,如下代码负责创建:
var httpUploadRequest=google.gears.factory.create("beta.httprequest");
当完成创建之后,则可以通过open方法连接服务器端的处理上传的URI上去。如下代码:httpUploadRequest.open("PUT", fileURI);
当要上传到服务器的时候,可以通过一个进度条或之类的方式表示文件正在上传中,这种情况可以通过一个回调函数有用户决定如何处理,如下代码:
httpUploadRequest.upload.onprogress = _onprogress();
httpUploadRequest.onreadystatechange = function()
{
switch(httpUploadRequest.readyState)
{
case 0:
//Uninitialized;
case 1:
//Open;
case 2:
//Sent;
case 3:
//Interactive;
case 4:
//complete;
break;
}
};
其中,代码中_onprogress由用户自己实现上传过程中的任务。
而当上传处理的时候,HttpRequest和
如果要上传文件,则可以通过send方法发送文件的内容,blob是以二进制字节流的方式发送数据。如下代码:
httpUploadRequest.send(file.blob);
本地桌面交互
前面已经介绍了Desktop类的访问本地文件的能力,下面我们再来讨论一下它的另一个功能就是在本地桌面创建到页面应用的快捷图标的能力。createShortcut方法就可以通过gears在桌面创建图标,图标的大小有四类:16x16、32x32、48x48 和 128x128。如果,在windows系统下可以选择把图标创建在桌面、开始菜单和快速启动栏。具体操作如下代码:
var desktop = google.gears.factory.create("beta.desktop");
var description = "This shortcut launches the Gears shortcut sample page.";
//图标的路径
var icons = {
"16x16": "icon16.png",
"32x32": "icon32.png",
"48x48": "icon48.png",
"128x128": "icon128.png"
};
desktop.createShortcut("Gears Shortcut Sample", // 标题
"hello_world_shortcuts.html", // 快捷方式连接的url
icons, // 图标数组
description); // 描述信息
执行上述代码如下图:
本地化
通过Gears的本地化,可以很容易的获得用户的时区、地理位置、所在地等信息。具体操作如下:
var geolocation = google.gears.factory.create('beta.geolocation');//创建本地化对象
然后,通过void getCurrentPosition(successCallback, [errorCallback], [options])可以获得用户的本地信息。
geolocation.getCurrentPosition(successCallback,
errorCallback,
{ enableHighAccuracy: true,
gearsRequestAddress: true });
这里我们可以看到,有两个回调函数,successCallbak表示获取本地化信息成功,errorCallback表示获取失败。若获取成功,我们可以把取得信息输出,如下代码:
function successCallback(p) {
var address = p.gearsAddress.city + ', '
+ p.gearsAddress.region + ', '
+ p.gearsAddress.country + ' ('
+ p.latitude + ', '
+ p.longitude + ')';
clearStatus();
addStatus('Your address is: ' + address);
}
其中,参数p是一个Position类,该类提供了一些属性获得地理位置。
后台处理
Gears提供了WorkerPool使得客户端的JavaScript代码可以在后台运行,从而不用通过阻塞的方式在页面工作。在页面操作的时候,可能存在大量数据的I/O操作,这样有可能使得UI操作被阻塞,那么通过Gears的WorkerPool就可以使得这类操作在后台进行。
Gears的WorkerPool实际上就是一个线程池,由于采用了池的方式管理线程,因此,要比多个线程效率高,并且在执行的过程中每个worker是不会共享任何状态。WorkerPool中的各个worker之间由于不是通过共享状态传递信息,所以有效的避免了冲突;但是,他们又是通过什么来传递消息呢?事实上,worker之间的消息传递是通过消息传递来完成的。
由上面我们知道Gears的WorkerPool是不会共享任何状态的,那么对于DOM,比如document或window对象也同样不能被共享。因此,只有在主worker才能获取DOM,而其它worker则不能。
Worker之间的消息传递通过sendMessage方法发送,在处理发送过来的消息的时候通过onMessage事件来接收并处理。
Gears网站
Google Gears 首页:http://gears.google.com/
Google Gears 下载:http://code.google.com/apis/gears/tools.html