由两篇文章组成的系列文章主要阐述如何在嵌入式 Linux 智能设备的应用程序中增加 Web 支持。第 1 部分,我们将会介绍嵌入式 Linux 智能设备开发的现状、Qt 和 WebKit 的概念。并以广告机和手持点菜机等应用为例,叙述在嵌入式 Linux 平台以及 Qt,WebKit 等技术的帮助下,如何在终端应用程序中添加网页浏览的功能,如何用 Web 技术取代传统 UI 技术,以及如何在智能设备上实现从 C/S 到 B/S 的开发模式的转换。
嵌入式 Linux 智能设备开发的现状
近几年,嵌入式 Linux 在智能设备中的应用发展的非常迅速。可以预见,嵌入式智能设备和我们的生活将会越来越密不可分。
Linux 在嵌入式系统中的应用可以分为两大类:面向服务类和面向应用类。典型的面向服务类系统有交换机、路由器、监控设备等;典型的面向应用类的系统有手机、PDA、机顶盒等。本文主要讨论面向应用类,特别是指带有网络和 UI 的应用系统。
在嵌入式 Linux 上进行带 UI 的应用程序开发是一件非常复杂的事情,主要涉及以下几个方面:
UI 系统
Linux 本身的 UI 系统并不统一,嵌入式版本上的 UI 系统更是五花八门,而且与其 PC 版本相比也有一些适应性的改变。而有些产品的开发甚至不使用 UI 系统,通过直接往 framebuffer 贴图的方式来实现 UI。而且与 PC 相比,嵌入式系统的性能问题,也让嵌入式的 UI 系统在表现上做出很多妥协。这些都使得开发难度增加,带来更多的不兼容问题。这些都使嵌入式 Linux 上的应用开发和移植变得更加困难,另外也使培养一名合格的嵌入式工程师的成本变的比较高。
厂商支持
对于一个嵌入式平台,其主芯片的生产商对这个平台影响巨大。一般来说,生产商会提供对某个或者某些 UI 系统的支持,但是他们不可能支持所有的系统。所以,选定一个嵌入式平台就意味着开发团队需要切换到这个平台所能支持的 UI 平台上。这个团队之前做的应用就需要移植到新的 UI 平台,而这个移植是非常麻烦的。
浏览器
嵌入式 Linux 的网络接口一般都支持 posix 的标准,但是嵌入式设备的浏览器则与 UI 系统一样是五花八门的。在应用的推动下,嵌入式 Linux 平台上的浏览器在近年发展也非常迅速。他们基于不同的 UI 平台进行开发(也有一些直接操作 framebuffer),对 Web 标准的支持和兼容性各不相同。比较简单的浏览器只能支持 HTML 标签,优秀的产品则能在兼容性上做到与 PC 平台上的浏览器几乎同样的水平。
服务器技术
很多嵌入式应用需要与服务器进行连接,点菜机就是一个典型的应用。手持智能设备端需要将用户的操作写入远程的服务器,然后远程的信息管理系统进行进一步的处理。这种类型的应用对于 PC 平台来说就是一个非常简单的数据库应用系统,数据库、远程调用、并发、中间件等技术已经应用了多年,而且还有众多成熟的企业应用的框架,可以灵活而快速的搭建出一个系统。但是这些在嵌入式平台都是不存在的,这意味着开发人员还需要用相当于 PC 平台十几年前的水平来进行开发,为了让嵌入式系统和服务器的数据库进行对接,开发人员还需要在服务器端编写一个专门的程序来充当桥梁的作用。笔者见过在不少项目里还需要直接控制 socket 来和服务器进行数据交换,这些对于 PC 平台都是不可想象的。另外开发一个支持多个客户端并发的稳定服务器程序并不是一件容易的事情,这些问题都会影响整个嵌入式开发过程的成本和质量。
如果一个公司希望在某个嵌入式 Linux 平台上开发一个包含了 Web 浏览的应用,而他自己之前并不拥有一个完善的平台的话,其开发团队首先需要选定一个 UI 系统,然后寻找一家做浏览器的公司,与其合作,再想办法将浏览器移植到自己的平台上。如果是需要在自己的应用程序中嵌入一个浏览网页的窗体,那么问题就会更加复杂,因为还涉及到与选定的浏览器进行代码或者模块级别集成的问题。
Qt 和 WebKit 简介
Qt 是一个跨平台的 C++ 图形用户界面应用程序框架,对 Windows、Linux、Mac OS X、Unix、Free BSD 等主要的操作系统均有支持。Qt 不仅包含了图形界面库,还集成了 Network、File、IO、Database、2D/3D、XML 等模块,基本涵盖了一个应用程序所需要的所有功能,这些让 Qt 成为最有影响力的跨平台框架,Linux 平台上的 KDE 就是基于 Qt 开发的。Qt Embedded 则是 Qt 针对嵌入式平台的版本,在嵌入式平台的 UI 市场占有很大的份额。
Qt 可以解决上一节所讨论的很多问题,因为其优异的跨平台性能,开发人员甚至可以在 PC 上进行开发调试,然后直接将代码放到交叉编译环境中生成嵌入式版本,这样的移植基本不需要改动代码。
WebKit 是一个开源的浏览器引擎,目前 Safari,Chrome 等浏览器均使用了 WebKit 作为核心。Qt 从 4.5 版本开始,集成了 WebKit 作为 Qt 的平台组件,用户可以像使用其他组件一样将 WebKit 引擎集成到自己的应用程序中,以提供 Web 的支持。
在应用程序中添加网页浏览的支持
通过网址 http://qt.nokia.com/downloads 可以找到 Embedded Linux 版本的最新 Qt 源代码。现在最新版本是 4.5.3。
WebKit 作为第三方资源可以在如下目录中找到:
/qt-embedded-Linux-opensource-src-4.5.3/src/3rdparty/WebKit/
Qt 中对 WebKit 做了封装,主要有以下几个类:
QWebView 最常用的类,这是一个窗体控件,可以用来渲染网页
QWebPage 被 QWebView 包含,表示一个 documentQWebFrame 被 QWebPage 包含,表示一个 frameQWebSettings Web 渲染的全局设置 QWebHistory 用于浏览的历史记录
QWebView 是最常用的类,接下来我们大概的介绍一下这个类的组成。
根据头文件定义,我们可以得知这个类与 Qt 中按钮、对话框等一样,都是由 QWidget 派生,可以当做一个通用窗体来使用。
class QWebKit_EXPORT QWebView : public Qwidget
这个类有如下的成员函数:
void load ( const QUrl &url );
void setHtml ( const QString &HTML, const QUrl &baseUrl = QUrl() );
这两个函数可以让 QWebView 加载网页或者显示一段 HTML 内容,是 QWebView 最重要的函数。
这个类还有几个重要的 slot:
void stop ();
void back ();void forward ();void reload ();
这几个函数也是我们平时浏览网页时常用的功能。
QwebView 类还有几个重要的 signal:
Q_SIGNALS:
void loadStarted (); void loadProgress ( int progress ); void loadFinished ( bool );
很明显,这几个 signal 是用来显示网页的加载过程。
接着我们通过代码来看 QWebView 是如何使用的。假设程序有一个主窗体 MainWindow,在 MainWindow 的构造函数中,有如下代码段:
清单 1. MainWindow 构造函数的代码段
QWebView* view = new QWebView ( this );
// 设置窗体左上角的坐标以及长宽
view -> setGeometry( 50 , 50 , 400 , 300 );
view -> show();
view -> load( QUrl("http://www.google.com") );
设备网络配置好之后,运行程序,我们就可以看到在窗体中有一个区域显示出 google 的主页(编译的时候要注意在项目的 pro 文件中包含 WebKit 的头文件路径和动态库)。可见,Qt 已经将 WebKit 做了很好的封装,子应用程序中加入网页浏览功能是非常方便的。
如果希望能知道网页加载的进度,可以通过如下的代码来实现:
首先实现槽函数的定义:
清单 2. 槽函数的定义
Private slot:
void setProgress(int progress)
{ // progress,即百分比进度
}
void loadFinished()
{ // 表示网页加载完毕
}
第二步连接 Qt 的信号与槽函数:
清单 3. 连接 Qt 信号与槽函数
connect(view , SIGNAL(loadProgress(int)), this, SLOT(setProgress(int)));
connect(view , SIGNAL(loadFinished(bool)), this, SLOT(loadFinished()));
这样,在程序中加一个进度条表示网页加载过程就实现了。
用 Web 取代本地 UI 的应用
在嵌入式 Linux 智能设备上有一个典型的应用:信息机,或者广告机。这种机器一般都带有一个屏幕,有些会有触摸屏。屏幕上会组合显示文字、图片和视频,或者提供简单的查询功能。这种类型的设备最先是由内置 PC 来实现的,在各种服务大厅供用户使用。现在普遍使用嵌入式系统来取代 PC,以降低成本。
我们在银行、通信运营商服务大厅、医院、电梯房等地方经常能看到各种各样的广告机。一个典型的屏幕显示情况如下:
图 1. 广告机屏幕示例linuxweb_14A9A/image001_thumb.jpg" border="0" alt="image001" width="244" height="152" />
这是组合比较复杂的情况,也有整个屏幕就是文字、图片或者视频的。与传统和大型软件开发相比,实现这样的功能看上去并不算很难。开发人员可能需要在嵌入式平台自己去实现字幕、图片和天气的显示组件或者模块(暂时忽略视频播放功能),然后在屏幕上进行显示即可。比较困难的地方在于以下几个方面:
内容显示
图片和字幕需要以某种格式进行存放,天气信息来源于 Internet,开发人员需要编写代码对这些内容进行显示,并根据不同规则对内容进行切换。如有以下的配置文件内容:
清单 4. 屏幕配置文件 1
<screen>
<duration>30</duration>
<pic>1.jpg</pic>
<text>1.txt</text>
<video>1.avi</video>
<weather>http://xxxxx.HTML</weather>
</screen>
<screen>
<duration>25</duration>
<pic>2.jpg</pic>
<text>2.txt</text>
<video>2.avi</video>
<weather>http://xxxxx.HTML</weather>
</screen>
...
...
开发人员需要编写一个解析器,能够解析这个 xml 文件,并且按照其中的规则进行内容的显示。
内容更新
如果需要对广告机的内容进行更换,维护人员则需要将内容按照这个格式进行编排。编排的效果是需要反复调整的,这个时候,要不就是每次都用一台广告机来看实际效果,要不然可能还需要专门设计一个预览程序。
显示布局
屏幕的显示布局很可能也是要变动的,那么意味着布局最好也是可配置的,折旧要求广告机程序能够解析并且实现显示布局的配置。如果说解析上面的配置文件并不是很麻烦的事情,但是如果配置文件变成下面这样,就不一样了。
清单 5. 屏幕配置文件 2
<screen>
<duration>30</duration>
<pic x=800 y=200 width=320 height=240>1.jpg</pic>
<text x=0 y=600 width=1024 height=240>1.txt</text>
<video x=0 y=0 width=800 height=600>1.avi</video>
<weather>http://xxxxx.HTML</weather>
</screen>
<screen>
<duration>30</duration>
<pic x=800 y=200 width=320 height=240>2.jpg</pic>
<pic x=800 y=400 width=320 height=240>22.jpg</pic>
<text x=0 y=600 width=1024 height=120>2.txt</text>
<text x=0 y=800 width=1024 height=120>22.txt</text>
<video x=0 y=0 width=800 height=600>2.avi</video>
<weather>http://xxxxx.HTML</weather>
</screen>
...
...
不但各种元素的位置可配置,图片、文本等的数量也发生了改变。这个时候,解析程序将变得相当复杂。当更多的需求出现,如要求配置滚动字幕的速度、背景颜色,要求图片和文字等内容可以单独配置刷新时间等,这样的配置文件不会比 HTML 标准简单,而解析程序的规模也将急剧膨胀。
综上,广告机的软件关键并不在于内容如何能显示出来,而是软件需要有复杂的解析能力,能够支持可配置的布局和内容。目前这些广告机的配置文件大多使用 xml 来存储信息,而一个能够同时解决复杂布局和内容显示的程序,实际上已经非常类似浏览器的概念了。那么,让我们从真正的浏览器的角度来看待广告机的这些问题。
如果把屏幕内容当成一个网页的话,屏幕布局、内容显示、更新、维护等都转换成了设计网页的问题,而最关键的解析程序的开发可以忽略,用已有的成熟的浏览器取代。这里的网页设计并不关系到网页服务器端的开发,因为广告机的内容大多是存储在本地,所以只需要直接设计页面。页面内容的更新,或者整个页面的更新都可以通过标准 HTML,或者 JavaScript 之类脚本里实现。对于“天气”播放功能的实现就更加简单了,之前的方式需要编写程序通过网络从远程获取数据然后显示,比较麻烦。转换成网页模式之后,只需要在网页中嵌入一个子网页,指向远程的服务器链接即可。可见,以广告机为例,在架构上使用网页来取代之前的模式,能充分利用已有的资源和工具,极大的减少开发的工作量。
我们再考虑另外一种应用:带交互的信息查询机。带交互功能的信息机主要提供给人们索引和查询信息的功能,信息被分类并且根据索引存储,信息机的解析程序通过与用户的交互,显示所需要的信息。实际上,交互和索引跳转是网页天生的特性,所以,同样可以采用网页和浏览器的模式取代编写本地程序进行交互和解析,可以把几乎所有的工作转换成网页设计,从而将开发工作量减到了最低。
从 C/S 到 B/S 的转换
在嵌入式智能设备的应用中,有很大一部分是嵌入式智能终端需要与远程的服务器进行连接,通过人机交互和数据采集来实现应用,比较典型的就是点菜机。
无线点菜机是一种很常见的嵌入式智能设备,大多采用 Windows CE 或嵌入式 Linux 作为操作系统。如果把点菜机当成一个 PC 系统,那么这就是一个非常典型的客户端 / 服务器架构的应用。
图 2. 无线点菜机系统示例linuxweb_14A9A/image002_thumb.jpg" border="0" alt="image002" width="244" height="218" />
如图 2 所示,点菜机通过 WIFI 与服务器相连,通过网络与服务器通讯进行点菜操作,厨房端也有客户端与服务器相连,根据点菜情况进行菜品制作的安排。忽略 PC 和嵌入式开发的差异性,这个应用的实现过程和原理与 PC 基本是一致的。不同的是,通过网络实现业务的调用,如我们在前面提到过的,这在 PC 平台上已经有了很多资源甚至成熟企业应用框架,但是在嵌入式 Linux 平台上几乎都没有。所以,开发人员需要自己来实现点菜机和服务器之间的业务调用,进而与服务器端的业务处理部分进行集成。
对于服务器而言,最重要的部分就是数据库,要远程的操作数据库,PC 平台有大量的数据库组件实现对各种数据库的支持,但是在嵌入式 Linux 平台就没那么丰富的组件资源可以利用。所以,开发人员需要在服务器端实现一个“代理”,点菜机通过“代理”对数据库进行操作。这个“代理”不一定很复杂,但问题是,它仍然会占用大量的开发工作量,消耗工作时间。另外一个问题在于,当这个系统功能需要改变时,比如希望在点菜机界面增加显示图片的功能,客户端和“代理”端都需要同步进行开发,因此维护起来也是比较麻烦的。
实际上,这一类的应用在 PC 上现在大多已经由 C/S 模式转向了 B/S 模式。既然现在嵌入式 Linux 平台已经有了 Web 的支持,那么在嵌入式 Linux 平台 B/S 是否也同样适用呢。对于点菜系统这样的应用,假如我们在 pc 平台已经用 B/S 模式进行了实现(与很多企业应用相比,这是比较简单的)。只要嵌入式平台支持标准 Web,那么直接用嵌入式客户端的浏览器,这套系统的迁移很可能只需要考虑嵌入式设备的屏幕尺寸问题,把网页显示调整一下而已。
除了点菜机之外,物流行业中广泛使用的条码扫描机也是典型的应用之一。当货物入仓之时,工作人员用手持智能终端扫描条形码,数据会上传到服务器进行处理。如果采用 Web 方式,嵌入式 Linux 端开发工作量就会大大降低,只需要读取条码,然后通过 Web 输入即可。