移动WebKit

移动领域对HTML5的发展起到了举足轻重的作用,HTML5标准得到了几乎所有智能移动设备的支持,随着移动领域的众多创新,标准化组织也将这些新功能带入了Web领域,如对各种屏幕的支持,触控,手势和一些新设备能力接口等

触控和手势事件
HTML5规范

先了解一下触控,手势事件域游览器默认行为的关系,举个例子当用户点击屏幕上一个触控点并且向上移动时,游览器面临艰难选择,对于用户触发的触控事件,可能有两个地方需要使用到触控事件:第一是游览器本身,游览器可能希望利用这个事件完成翻页动作;另一方面该触控点所对应的元素可能需要由自己来处理这些触控事件,而不是游览器来处理。目前,Web引入了两种域触控相关的技术,其一是HTML5 Touch Events,它基本上已经成了规范,得到了众多渲染引擎和游览器的支持和认可,其二是Gesture Event,由苹果公司设计并在Safari游览器中实现,目前没有得到其他众多游览器的支持。首先来总结下HTML5 Touch Events,目前已称为推荐的规范,并且得到了两家主流移动操作系统的游览器支持,该标准主要是定义如何将原始的触控事件以特定的方式传递给JavaScript引擎,然后再传递给注册的事件响应函数,这一规范在HTML5网页应用中比较成熟,网页开发者可以根据规范进行定义,其中最主要的接口是TouchEvent,下图上半部分表示一个传递给JavaScript注册函数的事件

interface TouchEvent:UIEvent{
  readonly attribute TouchList touches;
  readonly attribute TouchList targetTouches;
  readonly attribute TouchList changedTouches;
  readonly attribute boolean altKey;
  readonly attribute boolean metaKey;
  readonly attribute boolean ctrlKey;
  readonly attribute boolean shiftKey;
};
// TouchList是一组Touch对象
interface Touch {
  readonly attribute long identifier;
  readonly attribute EventTarget target;
  readonly attribute long screenX;
  readonly attribute long screenY;
  readonly attribute long clientX;
  readonly attribute long clientYl
  readonly attribute long pageX;
  readonly attribute long pageY;
};

根据标准中的定义,TouchEvent分成4种类型:touchstart、touchmove、touchend和touchcancel,它们分别表示触控点开始接触屏幕、触控点移动、触控点离开屏幕和触控点消失,最后一个类型理解起来有点困难,有时游览器取消该触控点可能应该其他一些原因,如它可能进入了其他的窗口等,TouchEvent继承自DOM的UIEvent,表明它有同其他事件类似的处理方式,不同点在于这个事件有一些不同的属性。

  • “touches”:表示当前屏幕韩总包括的所有触控点,“touches”是一个列表,如果触控点大雨1,表示这是一个支持多点触控的设备
  • “targetTouches”:表示的是当前所有起始于当前DOM元素的触控点,也就是如果一个触控点的“touchstart”事件发生的位置在该元素的区域内,那就会被包含在该列表中
  • “changedTouches”:表示发生变化的触控点,如果类型是“touchstart”,那就包含新的触控点,如果是“touchmove”,那就包含发生移动的触控点,而“touchend”就是触控点移出了屏幕

每个触控点都需要包含很多信息,主要是标记属性的唯一ID、触控的目标、屏幕位置、视图中的位置等,有了这些接口,JavaScript代码能够非常清楚的知道每个触控点的信息,就能够想本地代码一样使用能够它们来满足各种应用的需求。下面的代码展示了如何注册监听事件的处理函数,这同其他的DOM事件区别并不大,而且也只能注册在特定的元素(称为Clickable Element)上,如“div”等,因为TouchEvent有四种类型,示例代码定义了其中三种类型触控事件的处理函数,以“touchstart”为例,它会接受一个事件,就是之前定义的TouchEvent接口,为了避免同游览器行为的冲突,可以在最开始的时候调用“preventDefault”。

var targetElement = docuemtn.getElementById("ATouchableElement");
targetElement.addEventListener("touchstart", onTouchStartEvent, false);
targetElement.addEventListener("touchmove",onTouchMoveEvent, false);
targetElement.addEventListener("touchend",onToucheEndEvent, false);

function onTouchStartEvent(event){
  // 处理事件
  event.preventDefault();
  event.touches;
  event.targetTouches;
  event.changedTouches;
}

有了这些原始的触控事件,Web开发者可以在网页中使用JavaScript代码来识别这些原始触控事件并生成手势事件,如Long Press、Pinch、Swipe、Fling等手势事件。

工作原理

下图描述了WebKit处理触控事件所使用到的一些主要类和它们之间的关系:
这里写图片描述
最下层的WebWidget和WebView是WebKit的Chromium移植提供的接口,同之前介绍的一样,它们也是被Chromium项目的代码所调用,当Chromium接收到事件之后会将其传给WebViewImpl这个类来做处理,因为事件有多种类型,WebViewImpl类借助域PageWidgetDelegate类处理和区分这些输入事件,经过PageWidgetDelegate类处理后的事件被调用WebViewImpl类各个事件处理接口,而WebViewImpl类的这些接口基本上使用主框(Frame)的事件处理句柄EventHandler对象来处理事件,图中EventHandler包含两个函数,第一个是处理原始触控事件的函数,第二是处理手势事件的函数。WebKit除了接收原始的触控事件之外,还需要它的移植或者游览器提供手势事件,这些事件会触发WebKit的默认动作,例如“LongPress”事件,它表示手指在屏幕上长按一段事件,这需要游览器将其识别成手势事件然后传递给WebKit,当WebKit接收到这个事件之后,触发自己的默认动作,这里的手势事件包括一个或者多个手指触发的动作,WebKit并不会将这里的手势事件传递给JavaScript代码。对于多框结构的网页,事件首先由WebKit交给主框处理,WebKit会检查该事件是否需要由子框处理,如果是的话,WebKit会将该事件派发给子Frame,依此类推,这是一个递归的过程。当触控事件发生后,Chromium首先需要将触控事件保存,然后使用众多的手势识别器(Gesture Recognizers)来将其识别成手势事件,下面存在一个问题

  • Chromium是否需要将所有的袁术触控事件传递给网页?答案是否定的,如一些网页并没有注册监听函数来处理,那么就造成极大的浪费,因为这些事件的传递和处理是个稍长的过程,更为致命的是一个简单的用户擦偶走通常有非常多的事件,这极大的浪费的CPU等资源
  • 为什么需要Gesture Event传递给WebKit?因为是由游览器识别并将识别出结果的事件传递给WebKit,这客观上能够有效减少很多事件的传递
  • 除了发送TouchEvent和GestureEvent之外,也可能会发送MouseEvent,原因?由于目前还存在一些网页,它们需要监听鼠标相关的事件以完成特定的动作,如果Chromium不模拟这些事件,那么网页显然不能正常工作,但是某些鼠标事件可以模拟,如MouseDown其实对应于TouchStart,MouseUp对应TouchEnd等,但是MouseOver比较麻烦,比如一些网页需要根据当前鼠标悬浮事件来显示一个菜单,这对于触控设备是一个问题

对于Chromium来说,事件的处理还是相当复杂的,因为需要三种类型的事件并将其传递给WebKit,由于触控事件最初是应用在移动设备上的,所以这里也主要以Chromium的Android版为例,在Chromium的Android版中,所有的事件都是有Android系统传送过来的,这也意味这事件的处理首先在Java层,当然是在Browser进程的主线程中,如下图所示的层次结构图和相关层次中的基础设施,Java层主要包含两个类:

  • ContentViewGestureHandler:它主要有几个任务,首先需要通过相应的设施来决定是否酉原始的触控事件,这依赖域WebKit,在每个“touchstart”事件开始的时候,需要进行HitTest检查,该动作检查当前触控点所对应的元素,然后检查该元素是否注册了监听事件的函数,如果是需要将原始事件传送给WebKit,其次是各种手势事件的识别器,它们能够对WebKit所需要的各种手势进行识别并传递给WebKit,最后根据需要模拟鼠标事件
  • ContentViewCore类:主要负责将C++中的功能桥接到Java层,并将Java中处理好的事件到呢个信息桥接到C++代码中,它对应C++中的类是ContentViewCoreImpl

这两个类主要负责Java层的事件处理和传递:
在Java层之下是RenderWidgetHostView类,它表示一个网页的视图,虽然是Browser进程中的代理类,表示的是Renderer进程中相应的网页视图,被ContentViewCoreImpl用来将事件传递给Renderer进程,Chromium通过IPC机制来完成传递,Browser进程中的基础类是ImmediateInputRouter,而Renderer进程中的基础类是RenderWidget类,在Renderer进程中,RenderWidget在Chromium中表示网页的结构,它拥有前面WebKit定义的接口类WebWidget,具体见下图:
这里写图片描述

启示和实践

网页除了可能需要自身处理触控事件意外,还有一个比较特别的问题,那就是对于一个为移动设备定制的网页,它可能不需要使用缩放网页或者不需要翻滚网页,因为开发者已经考虑并设计出了适合移动设备网页阅读的网页,根据上面的描述,网页开发者可以注册事件的响应函数并调用“preventDefault”函数来阻碍游览器执行默认行为,问题是这个方法只是针对某个元素而已,而不是整个网页,只是当手指触控到该元素的时候才禁止默认行文,解决这一问题的方法是将函数注册到区域更大的元素,如下使用“body”元素可以解决这个问题,除此之外还可以使用“meta”标签

  function handleEvent(event){
    event.preventDefault();
  }
  document.body.addEventListener('touchstart', handleEvent, false);
  document.body.addEventListener('touchmove', handleEvent, false);
  document.body.addEventListener('touchend', hanldeEvent, false);
移动化用户界面

HTML5为移动领域做了大量的工作,其中“meta”标签中的众多设置值能够帮助提供非常好的移动用户体验,一个典型的例子就是上面提到的用该标签来控制网页缩放,下面代码使用了一些JavaScript代码来完成,而实际上“meta”标签能够非常简单地完成这一目的

<meta name="viewport" content="user-scalable=no">

上述代码能够将缩放功能取消而不需要相对负责的JavaScript代码,不过“meta”标签只能用来控制缩放,没有能力解决不能翻页的问题,而WebKit很好的解决了这个问题,首先同Viewport相关的功能,使用能够meta标签最常见的设置就是“viewport”,它表示当前可视的区域,因为设备的大小有差异,所以如何使用网页的宽度适合屏幕的宽度就显得非常重要,方式如下:

<meta name="viewport" content="width=device-width, initial-scale=0.9, minimun-scale=0.5, maxium-scale=1.0,user-scalable=no">

上面的代码设置的名字是viewport,视窗的宽度是设备的宽度,而初始缩放大小是0.9,最小的缩放比例是0.5,最大的缩放比例是1.0。而且不允许用户使用手势来缩放它们,但是这只是解决了部分问题,因为如果设备差异特别大,那么过大的缩放比例对用户的体验是灾难性的,用来应对这个灾难的是响应式设计和“Media Queries”技术,其次是全屏游览,因为移动设备通常屏幕较小,所以游览器的地址栏和移动系统上的状态栏会占用较为可观的可视区域,因此Safari提供了一些设备来解决这个问题,就是使用全屏游览模式,代码如下:

<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">

不过目前仅有ios系统上deSafari游览器提供类似的支持,还有一种并不完善的方式,但较为通用:

window.addEventListener('load', function(e)) {
  setTimeout(function() { window.scrollTo(0,1); }, 1);
}, false);

最后是图标的设置,为了让网页在移动设备中也能像其他应用一样,可以设置该网页的图标,使用的方式是使用“link”标签设置,在Android游览器中的方式是使用如下属性:

<link rel="apple-touch-icon-precomposed" href="/path/to/icon/image" />

响应式设计其基本思想是根据不同分辨率或者说不同大小的屏幕,设计不同的布局,那么游览器虽然知道当前的分辨率和屏幕大小,但如何将开发者为该屏幕设计的网页布局应用在当前网页的渲染中就要用到CSS规范中的“Media Queries”技术。

其他机制
新渲染机制

为了移动领域更好的用户体验,渲染机制所做的改进主要是提升渲染性能来增加响应的速度,下面主要介绍三个方面的技术:Tiled Backing Store;线程化渲染;快速移动翻页。目前主流的地洞设备上,触控操作是比不可少的用户交互方式,同桌面系统不一样的是,网页的渲染结果需要对用户的相应度有很高的要求,但移动设备的能力比桌面及其的年国内管理要差一些,因此在最早的QtWebKit中引入了Tiled Backing Store机制,其核心思想是使用后端的缓存机制来预先绘制网页和减少网页的重绘动作,也就是使用空间换时间的思路,最初这一思想出现在软件渲染中,使用CPU分成瓦片块(Tile)的内存来保存绘制的网页内容,不同点在于它是使用CPU来分配并保存这些瓦片块,而且通常会超过视窗(Viewport)大小,这同样是一种典型的用空间换时间的做法。随着移动设备进入多核时代,如果渲染过程仅仅是由一个线程来完成,这不能不说是一个巨大的浪费,而且,同桌面系统强大的单核能力不同的是,因为耗电等原因,单核的能力明显处于一个稍差的阶段,所以将渲染过程分成若干个独立的步骤,然后使用不同的线程来完成其中的某个或者几个步骤可能称为未来WebKit渲染引擎一个重要的方向,特别对于移动领域来说尤为重要。

其他机制:

为了更好的支持移动设备,WebKit引入了一些新的机制,这里主要介绍两种:Application Cache和Frame Flatterning,也就是处理网页的多框结构。移动设备因为其移动的特性,需要能够提供离线游览网页对的内容,而应用缓存(Application Cache)这一新支持的机制能偶支持离线游览,同时还能够加速资源的访问并加快启动速度,它的基本思想是使用缓存机制并缓存那些需要保存在本地的资源,开发者可以现实指定那些是需要缓存的资源,并且使用起来非常简单:

<html manifest="app.appcache">
...
</html>

只是需要在“html”标签上加入属性“manifest”,指向一个文件,该文件格式如下所示,依稀来定义哪些资源需要缓存:

CACHE MANIFEST
# 需要缓存在本地的资源
CACHE:
app.html
app.css
app.png
app.js

不仅如此,规范还提供了接口来控制和访问网页中应用缓存的状态信息等,下面的例子使用规范定义的接口来更新缓存的内容,首先注册一个回调函数,当更新后触发该函数,如果更新成功,那么需要将旧的缓存清除掉,填充新的缓存内容,这就是swapCache函数的作用,如下代码所示,在代码最后调用update函数就可以完成触发更新资源的目的了,有了这些,理想使用就变得很容易:

var appCache=window.applicationCache;
appCache.addEventListener("updateready", function(event)) {
  if (appCache.status == appCache.UPDATEREADY) {
    appCache.swapCache();
  } else {
    ...
  }
});
// 重新下载缓存的资源
appCache.update();

下面介绍框结构在移动设备上的特殊处理,前面介绍过网页的框结构,其中讲到网页可能包含多个框,每个框都可以包含一个滚动条(如果该框在布局中的大小要比实际的内容小),也就是框内部是可以滚动的,当光标在框中的时候,滚动鼠标中键能够滚动该框的内容,但是在移动设备上,因为屏幕和触控的缘故,用户可能不知道需要滚动网页还是框,因此,iframe和frameset等多框结构很难在移动设备上使用,为此,WebKit使用了一种称为“Frameset Flatterning”的技术,该技术的含义是将框中的内容全部显示在网页中,通俗来说就是将框中的内容平铺在网页中,而不用设置滚动条,也就意味这,用户只是滚动网页,当然框中的内容也是包含在网页中,也会随着网页的滚动而发生变化。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值