用Web技术开发客户端(一)
2012-12-27 20:35 lefan 阅读(1636) 评论(0) 编辑 收藏 举报范怀宇(@duguguiyu)分享了《豌豆荚2.0重构时遇到的坑》,其中有段用“Web的思想”做PC客户端,引起了我强烈的好奇,通过慢慢消化,也使我对豌豆荚、Web、开源,有了新的认识。
一、用“Web的思想”做PC客户端
“全新的豌豆荚2.0的架构其实看上去和Web应用比较相似。前端页面主要基于Webkit内核,用Html、CSS、JS的技术绘制界面,满足标准的Web规范,甚至可以跑在Chrome上来测试。其他需要和Windows的一些原生效果比较相似的界面部分,我们从Chromium中抽取了一套UI框架来构建。
在后端的逻辑主要分成两个部分,一个是平台层,提供基础的功能服务,比如说与手机通信,和服务端通信,和操作系统通信等等。除此之外,我们把业务逻辑封装成不同的服务,每一个服务最重要一点是独立,彼此之间完全没有耦合。服务和服务之间,后台和前端之间,全部通过通信层来进行交互。在通信层上流转的数据,我们称之为communication数据,这些数据都是用ProtocalBuffer来描述。
通信层是整个架构比较核心的部分。它的协议定义是来自于一个开源的项目——Onering,这个项目的初衷也是受了豌豆荚1.0的启发,觉得1.0采取的基于Web开发客户端应用的架构很符合未来的发展,在这个基础上,他们做了一些协议的定义,把整个通信方式模拟得更像一个Http请求,把通信端分成三个部分,一个是前端,一个是后端服务,另一个是操作系统,定义了这三个端,六个方向的通信实现的策略。我们主要参考了其中的协议定义,在实现方面,Onering项目原来实现会比较简单和粗放。在豌豆荚的实现中,我们使用了定义的Webkit和C++语言作为前后端的实现基础,用Protocal Buffer来描述通信协议的数据。”
其中用到开源软件有Webkit、Chromium和Onering等,下面根据网上的内容简单汇总了相关信息。
1Webkit:
1.1 webkit结构分析
Webkit主要包括三个模块:WebCore 渲染引擎、JavaScriptCore 脚本解析引擎和WebKit 外壳。其中,WebCore 渲染引擎模块及JavaScriptCore 脚本解析引擎模块共同完成内核功能,组成了浏览器内核。另外,WebKit 也是整个浏览器引擎工程的名字。
在WebKit 工程中,不同的文件夹就相应的对应了不同的功能模块。其主要的功能模块如:一、WebKit:浏览器外壳模块,它隐藏并选择WebCore 渲染引擎到当前平台。WebKit 实际上相当于一个抽象化的浏览器外壳,它隐藏浏览器渲染引擎WebCore,并向UI 曾提供一些抽象的功能。
二、JavaScriptCore:JavaScript 脚本解析引擎,其中:KJS:JavaScript 内核。JavaScript 内核支持如下内核类:String(字符串)、Math (计算)、Number(数字)、Boolean (布尔型变量)、Date (日期)、Array(数组)、Regular Expression (正则表达式)JavaScriptCore 是可扩展的。API:基本JavaScript 功能,实际就是JavScript 的对外接口函数库。DerviedSource:yacc 自动产生的代码,主要用于Java Script 脚本的解析。WTF:KDE 的C++模板库。
三、WebCore:是整个项目的核心,用来实现渲染引擎,解析Web 页面,生成一个DOM 树和一个render 树,并最终render 这个树。其具体模块如下:1.Page:与外框相关的内容(Frame,Page,History,Focus,Window);2.Loade:加载资源及Cache;3.HTML:DOM HTML 内容及解析;4.DOM: DOM CORE 内容;5.XML:XML 内容及解析;6.Rendering:排版功能;7.CSS:DOM CSS 内容;8.Binding:提供DOM 与JavascriptCore 绑定的功能,并提供对JavascriptCoreAPI 的扩展,实现了Web 的主要类,如:窗口类、文档类、表格类、单元类等。
还包括Bridge:与其它功能绑定的功能,如:DOM,C,JNI,Plugins 等。Editing:所有与编辑相关的功能。DerviedSource:yacc 自动产生的代码,主要是与CSS 模块一起负责对CSS的支持。ForwordHeads:头文件,无实际意义。Plugins:插件功能。Storage:与数据库存储相关的功能。ICU:多语言支持,IBM ICU 库。History:与历史纪录相关功能。Platform:与平台相关的功能,如图形图像、字体、Unicode、IO、输入法、网络等。
图1 Webkit体系结构
图1 表示了WebKit 主要功能模块之间的依赖关系。其中,渲染引擎WebCore 以及JavaScrip t 脚本解析引擎JavaScriptCore 是我们将要移植的WebKit内核。在移植的基础上,我们将开发基于CAR 构架技术和欣浏览器外壳,该外壳其实相当于图中的WebKit 模块,它将隐藏浏览器渲染引擎WebCore 以及JavaScript 脚本解析引擎JavaScriptCore,并向UI 曾提供一些抽象的功能。
1.2解析流程
图2.webkit解析流程图
如图2所示,webkit解析流程为:通过CURL获得网站的stream解析划分字符串,通过Dom Builder 按合法的html规范生成Dom 树,如果有javascript,JSEngine就通过ECMA-262标准完善Dom 树,把Dom 传给LayoutEngine,进行布局,如果有CSS 样式,就通过CSSParser 解析,最后Rendering out出来。
2.Chromium
Chromium 是 Google 的 chrome 浏览器背后的引擎,目的是创建一个稳定、快速的通用浏览器。Chromium是一个由Google主导开发的网页浏览器。以BSD许可证等多重自由版权发行并开放源代码。Chromium的开发可能早自2006年即开始,设计思想基于简单、高速、稳定、安全等理念,在架构上使用了Apple发展出来的WebKit排版引擎、Safari的部份源代码与Firefox的成果,并采用Google独家开发出的V8引擎以提升解译JavaScript的效率,而且设计了“沙盒”、“黑名单”、“无痕浏览”等功能来实现稳定与安全的网页浏览环境。Chromium是Google为发展自家的浏览器Google Chrome(以下简称Chrome)而开启的计划,所以Chromium相当于Chrome的工程版或称实验版(尽管Chrome自身也有β版阶段),新功能会率先在Chromium上实现,待验证后才会应用在Chrome上,故Chrome的功能会相对落后但较稳定。关于Chrome介绍,请看@duguguiyu 的Chrome源码剖析,共5个系列。
3.Onering
桌面应用框架 OneRing是一个跨平台的桌面应用框架。和Adobe AIR类似,它支持用html/js/css制作用户界面,与之不同的是,它的应用为本地程序,可以直接访问操作系统的数据。 一个OneRing应用程序分为两个部分:框架部分和应用部分。 框架部分为通用框架,各应用都一样。其提供各操作系统上的界面展现,为本地窗口内嵌一个WebKit浏览器,并提供一致的js接口让应用和操作系统功能进行交互。 框架以运行时库的形式提供。 框架以系统原生语言编写,提供其他语言的绑定。 应用部分为一个web server,负责应用逻辑,用html/css描述界面,用js提供用户交互。
3.1运行流程:
1.应用启动时,会加载框架的运行时库,注册应用url的访问方法(如WSGI),并调用框架的loop函数。
2.loop函数会访问应用的 /init URL,得到一个json数据,描述初始应用窗口的相关参数,如位置、大小、窗口属性、初始页面url等。
3.框架根据该数据创建窗口,并让该窗口内的浏览器访问初始页面url,渲染用户界面,然后等待UI事件。
4.用户在界面上操作时,可以通过超链接改变整个窗口内容,也可以使用AJAX技术更新窗口内部分内容。
5.应用可以让浏览器调用ONERING名字空间下的js函数,和操作系统进行交互,该名字空间由url onering://onering/onering.js 加载。
6.应用通过 bind(event, function) 函数监听窗口更改大小、移动等操作系统UI事件。
7.可以使用pub/sub机制主动推送消息给浏览器。
8.调用 ONERING.exit() 可以退出应用;所有窗口都关闭后也会退出应用。
3.2各组件之间的交互
一个OneRing应用中,存在三个需要互相通讯的组件:
1. 操作系统 OS ,控制窗口行为(如最小化窗口),及操作系统相关界面元素(如系统通知图标)
2. 运行在WebKit内的javascript,控制界面内元素(如程序界面里的按钮)
3. WSGI应用,控制HTML/JS的生成逻辑,以及应用相关的后台逻辑
js -> os
当js需要通知os对js所在窗口做某个行为(如最小化),通过调用 onering.js 中的get_current_window()返回值(为Window对象)的相应方法实现:
当js需要os执行整个应用层面的操作时(如结束应用),通过调用 onering.js 中的函数实现:
当js需要os创建一个新窗口时,通过调用createWindow函数实现,并获得新建窗体的句柄实例:
当js需要向另一个窗口做某个os行为时(如隐藏另一个窗口),通过调用窗体的句柄实例的方法实现:
os -> js
js可以通过bind机制,关注操作系统发生的时间(如窗口大小改变):
js -> app
js可以通过类AJAX调用,从app获取数据。
app -> js
app希望向窗体内的js主动推送消息时,可以采用pub/sub机制。 首先js通知框架自己关注的事件,然后当app希望发送消息时,调用onering框架提供的publish方法。
二、产品的形成
“在豌豆荚2.0当中,其实我们使用了大量的开源软件。我记得在第一次提交代码时,我提交了180万行代码,其中包含了很多开源软件的实现。其中,最核心的一部分是从Chrome开源项目中抽取的基础架构部分。Chrome已经成为了业界标杆,不仅是所有的浏览器,很多现在Windows的程序也会同样采取Chrome的架构以及Chrome的一部分的代码实现。Chrome给豌豆荚带来的最重要的东西是编程模型,每个线程都有消息循环,跨线程的操作都是异步调用。因此,在实现业务时不需要关注数据访问时的并发性问题。还一个很重要的部分,Chrome对操作系统的原生API进行封装,提供了更为建议可靠的API,使得开发时可以尽量少地和操作系统API打交道。此外,它还对很多常用算法进行了封装,比如Md5,比如Sha,等等。Chrome也可以对STL做了很好的加强,对更丰富数据结构和API支持。
其实有一个基于Chrome的开源的项目叫Chromium Embeded Framework。这个项目抽取了Chromium中核心的部分,整个架构和豌豆荚2.0采用的颇为相似,现在也是被很多公司采用来开发软件。整个豌豆荚2.0的架构总结一下,其实很重要的一点就是,我们使用了一个比较新的技术的尝试。”
在前人的肩膀上去创造一点点,就是进步了。Apple将KHTML 发扬光大,推出了KHTML 改进型的WebKit 引擎,获得了非常好的反响,并在此基础上推出浏览器Safari。WebKit 内核在手机上的应用十分广泛,例如Google 的手机Gphone、Apple 的iPhone, Nokia’s Series 60 browser 等所使用的Browser 内核,都是基于WebKit 的。
也有浏览器移植WebKit 的渲染引擎WebCore 以及JavaScript 脚本解析引擎JavaScriptCore 作为自己的内核。WebKit 内核的移植主要涉及编译环境的搭建、编译分支的选择、WebCore 渲染引擎与和欣图形系统的配合、WebKit 内部数据类型与CAR 自描述数据类型之间的转换、本地化支持等问题。这些问题的解决也是创造产品的过程。
参考:1.富交互应用前端架构(视频) 来自Cat Chen,
2.duguguiyu 的Chrome源码剖析,
3.陈洪光.基于和欣平台的嵌入式浏览器的研究和实现