- UID
- 1029342
- 性别
- 男
|
Web 与本地应用的关联
虽然在嵌入式 Linux 智能设备中采用 Web 支持已经解决了很多问题,但是还有一些和设备相关的特殊功能是 Web 支持不能提供的。比如广告机中的音视频播放功能,条码扫描机的模式识别功能,还有与某种外设的通信等。这些并不是 HTML 和浏览器的标准所包含的,而是需要本地应用的支持。既然我们希望使用 Web 和 B/S 等技术来实现我们的应用,那么这些本地应用功能也应该由 Web 来控制。比如说广告机的视频播放,实际的播放是由本地应用实现的,但是什么时候在什么位置播放什么视频应该由 Web 来决定。并且广告页面内容的编辑也应该在网页的 HTML 中体现,而不需要另外一套播放控制机制。
但是想要由 Web 来控制本地应用存在一个问题,这些本地应用的调用没有一种统一的机制。有的可能通过驱动,有的可能是通过 I2C、串口的通讯口,有的可能是第三方提供的库,还有的可能是与其他进程的通信。可以说,除了他们大多用 C/C++ 语言进行开发之外,几乎没有什么共同点。
那么现在我们要解决的问题就是,当 QWebView 渲染一个网页的时候,如何让我们在网页里编写的一些特定的 HTML 能和我们的 C/C++ 代码关联起来。幸运的是,Qt 封装的 WebKit 提供了多种方法使我们可以很好实现这个关联。接下来,我们会以几种应用场景为例来讨论 Web 和本地应用关联的几种实现方法。
截取 request 的方法
首先我们介绍第一种应用场景:某嵌入式智能设备需要实现下面的功能,用户点击网页上“更新”的链接,设备就会下载指定的 Firmware 并且进行更新。
为了实现这个功能,客户端的浏览器需要在用户点击了某个特定的 Link 之后,启动系统的更新过程。包括获取最新 Firmware 的地址,进行下载,最后更新设备。Firmware 的更新过程和设备硬件相关,标准浏览器不能实现这个功能,因此我们必须“截获”用户的这个请求,然后使用本地代码来完成整个更新过程。
为了实现截获用户的这个 HTML request,我们先分析一下 QWebView 的结构。
图 1. QWebView 的结构图
QWebView 使用 QWebPage 来实现页面,QWebPage 使用 QWebFrame 来实现页面元素。当页面发出一个 Navigation 的 request 时,QWebPage 会来进行处理。这个时候有一个函数会被调用:
bool QWebPage::acceptNavigationRequest ( QWebFrame *frame, const QWebNetworkRequest &request, QWebPage::NavigationType type )
这个函数会在发生 Navigation Request 的时候获取到触发事件的页面元素、request 内容和类型。如果函数如果返回 false,浏览器将忽略这个 request。
我们可以从 QWebPage 派生一个子类,重写 acceptNavigationRequest,在发现特定 request 内容的时候,做出自己的处理。假设目标地址是 http://xxxx.com/update/Firmware.bin,实现如下:
清单 6. acceptNavigationRequest 函数的定义和实现
class QMyWebPage : public QwebPage { protected: bool acceptNavigationRequest ( QWebFrame *frame, const QWebNetworkRequest &request, QWebPage::NavigationType type ); ... ... }; QMyWebPage::acceptNavigationRequest ( QWebFrame *frame, const QWebNetworkRequest &request, QWebPage::NavigationType type ) { if( type == QWebPage::NavigationTypeFormSubmitted ) { QString str = url = request.url().path(); // 如果是特定的目标 if( str == “http://xxxx.com/update/Firmware.bin” ) { // 从 link 中获取 Firmware 地址 get Firmware addr from path // 下载 Firmware download Firmware // 更新设备 Firmware update Firmware // 返回 false 让浏览器不再处理这个 request return false; } } return QWebPage::acceptNavigationRequest ( frame, request , type ); } |
上面实现部分中获取、下载和更新 Firmware 部分用说明性文字来表示,不是真实的实现代码,用户可以根据自身的需求改写这部分本地代码。
除了实现具体功能之外,我们还需要让 QMyWebPage 被 QWebView 使用。这是通过 QWebView 的 setPage 调用实现的,可以在构造 QWebView 实例的时候加入:
QWebView* Webview = new QWebView ( this );
QMyWebPage* page = new QMyWebPage ();Webview -> setPage ( page ); // 让 WebView 使用我们的 QwebPage
至此,我们实现了当页面发生了点击 http://xxxx.com/update/Firmware.bin 的时候,截取了这个 request,并让我们的本地代码能被适时的调用运行。
acceptNavigationRequest 还可以被用在另外一种场合,某些网站会根据设备的 mac 地址决定是否提供下载服务,让设备在请求下载链接的时候,要求其在头信息里提供 mac 地址。我们注意到 acceptNavigationRequest 的参数里有 QWebNetworkRequest 的变量,这个类实际上就包含了头信息,虽然在这个变量在这里是一个不可更改的引用,但是我们可以保留这个信息,复制一份,在头信息里加入 mac 信息,然后让 QWebView 主动进行一次下载请求,从而实现在头信息里添加自定义内容的功能。
在页面中执行自定义的 JavaScript 的方法
接着我们介绍另外一种应用场景:手持条码机对准货物的条码,按键扫描之后,该货物的信息立刻在条码机上显示出来。
这个功能是一个很典型的网页查询应用,我们可以假设条码是被手工输入到网页上的编辑框,然后 submit 一个请求,服务器返回该条码表示的货物信息。所以,如果在按键扫描之后,条码号能被填入网页上的编辑框并且触发一个 submit,这个功能就可以实现。
Qt 封装的 WebKit 可以在已加载的页面中插入执行用户自定的 JavaScript,这是通过 QWebFrame 的 evaluateJavaScript 接口来实现。
QVariant QWebFrame::evaluateJavaScript ( const QString& scriptSource );
下面我们通过几个例子来演示如何执行 JavaScript。
假设我们的页面中有一个编辑框,名称为“code”,它的旁边还有一个按钮名称为“query”。扫描机对准条形码之后,用户按下一个按键,触发了 Qt 程序窗体 form 中的一个消息响应函数,在消息响应函数中通过如下的语句可以设置编辑框中的内容: |
|