《WebKit技术内幕》学习之十五(2):Web前端的未来

2 嵌入式应用模式

2.1 嵌入式模式

读者可能会奇怪本章重点表达的是Web应用和Web运行平台,为什么会介绍嵌入式模式(Embedded Mode)呢?这是因为很多Web运行平台是基于嵌入式模式的接口开发出来的,所以这里先解释一下什么叫做是嵌入式模式,并了解一些典型的案例。

因为通常来讲浏览器是一个本地应用程序,当用户打开一个网页时,它提供可视化界面。但是,很多其他本地应用程序(如邮件客户端使用该接口来打开邮件,因为有些邮件是使用HTML格式来编写的)希望使用网页渲染和HTML5的功能,同时又不需要浏览器的某些功能(如标签管理等),这时它们希望渲染引擎能够提供一组接口,本地应用程序能够使用这些接口来渲染网页,同时又能使用本地代码编写其他一些能力,这就是嵌入式应用模式。所谓的嵌入式模式是指,在渲染引擎之上提供一层本地(如C++或者Java)接口,这些接口提供了渲染网页的能力,渲染的结果被绘制到一个控件或者子窗口中,本地应用通过本地接口来获得渲染网页的能力。

目前嵌入式应用模式被广泛地使用,很多本地应用都需要有能力渲染网页,下面介绍两个非常典型的基于Webkit渲染引擎的嵌入式接口或者说是框架。

15.2.2 CEF

CEF全称Chromium Embedded Framework,它是一个开源项目,目的是提供一套嵌入式的本地代码(C/C++等)编程接口,最初的版本是基于早期的Chromium开源项目中的RendererHost类和很多其他内部接口开发而来的,这些内部接口变化很大,而且是单进程架构。在新的CEF3中,它主要依赖于相对稳定的Content API来实现的。

CEF之所以选择Chromium项目作为基础,是因为Chromium对HTML5能力提供了非常好的支持,并且Chromium支持Windows、MacOS和Linux等操作系统,所以CEF项目被众多用户所使用。

为了清晰地了解WebKit、Chromium和CEF之间的关系,图15-1描述了WebKit、content API、浏览器、Content Shell和CEF3的层次关系。Chrome浏览器、Content Shell和CEF3三者都是基于Content API开发的,它们只是有些不同的实现,服务于不同的应用场景而已。

图15-1 CEF在Chromium层次结构中的位置

早在Content API出现之前,CEF便已出现,它能够提供嵌入式的框架,可以让渲染网页的功能方便地嵌入到应用程序中。CEF依赖于Chromium开源项目,所以Chromium对HTML5的支持和性能上的优势,都得以继续在CEF中体现出来。但是,根据实际测试的结果来看,对于最初的版本,情况可能并非如此。首先,它对GPU硬件加速的支持不是很好,这是因为它会把GPU内存读回到CPU内存,速度非常慢。再次,因为基于Chromium的接口经常变化,所以CEF经常需要发生变化,这对维护人员来说是件很头痛的事。

得益于Content API的出现,CEF的作者也基于该接口开发了CEF3。CEF3在保持其提供的接口基本不变的情况下,借助Content API的能力,对HTML5和GPU硬件加速提供了较好的支持。它的核心变为调用Content API的接口和实现Content API的回调接口,来组织和包装成CEF3自己的接口以被其他开发者所使用。其好处是,CEF3的接口相对比较简单,使用起来方便,同时不需要实现很多Content API的回调接口,缺点就是,如果需要使用Content API的很多功能,CEF3的接口可能做不到,或者说只能通过直接调用Content API接口来完成。下面简单介绍一下CEF3的接口类。

  • CefClient :它是一个回调管理类,包含5个接口类,用于创建其他的回调类的对象。CefLifeSpanHandler回调类,用于控制弹出对话框的创建和关闭等操作。CefLoadHandler回调类,可以用来监听frame的加载开始、完成、错误等信息。CefRequestHandler回调类,用于监听资源加载、重定向等信息。CefDisplayHandler回调类,用于监听页面加载状态、地址变化、标题等信息。CefGeolocationHandler回调类,用于CEF3向嵌入者申请地理位置等权限。
  • CefApp :与进程、命令行参数、代理、资源管理相关的回调类,用于让CEF3的调用者们定制自己的逻辑。
  • CefBrowser :它是Renderer进程中执行浏览相关的类,如网页的前进、后退等。
  • CefBrowserHost :Browser进程中的执行浏览相关的类,它会把请求发送给CefBrowser类。
  • CefFrame :该类表示的是页面中的一个网页框(Frame),可以加载特定URL,在该运行环境下执行JavaScript代码等。
  • V8 :CEF3提供支持V8 扩展的接口,但是这里有两个限制。第一,V8 扩展仅在Renderer进程使用;第二,仅在沙箱模型关闭时才使用。

CEF项目虽然不是特别复杂,但是因为带来了好处,使得它受到了开发者的欢迎,特别是在桌面系统中使用它来渲染HTML5网页。

2.3 Android WebView

熟悉Android系统和HTML编程的开发者可能听说过Android提供的一个重要类android.webkit.WebView,它继承于View类(一个视图控件类),这是它同其他很多控件的相似之处。不同之处在于,它能够用来渲染网页。WebView是一个典型的嵌入式模式的接口。当前(也就是Android 4.3以前的版本),WebView本身只是一个编程接口,它的内部实现是基于现有的默认WebKit内核(Android默认浏览器是基于WebView构建),虽然它们都叫WebKit,但不同于Chromium所使用的WebKit内核。

目前,WebView被广泛应用在众多的Android本地应用程序中,通常笔者称之为混合应用程序。遗憾的是,它对HTML5的支持不是特别好,而且也没有新的功能被加入进来,同时,Chromium的Android版正在积极向前发展,更多针对该平台的HTML5能力和优化已经逐步被实现和采用,那么是否也可以使用Chrome的内核来实现该WebView呢?答案当然是肯定的。

目前,该项目已经启动并取得了良好进展,核心思想在于保持WebView的接口兼容性,同时将内部的实现从当前默认WebKit内核变成了Chromium的内核,但是原有的WebViewAPI保持不变,这样对于WebView的用户来说,调试代码时不需要做任何改变,便可以使用功能更多性能更好的渲染内核了。在Android KitKat 4.4版本后,Google公司已经使用Chromium项目来实现WebView接口,不过它仍然同Chrome的Android版浏览器存在比较大的区别,如进程模型(Chromium的WebView使用单进程)、不同绘图模型、功能支持(Chromium的WebView在Android 4.4中不支持WebGL、WebRTC和WebAudio等)等方面存在比较大的差异,而且性能也不是很好。

开发者可以通过编译目标"android_webview_apk"来尝试一下它的功能,这也是基于WebView的一个简单的应用程序实例,就如同Content模块和Content Shell的关系。不过这不是真正的WebView的实现,因为Chromium的WebView仍然要求同Android的系统代码一起编译,这里只是一个简单的测试APK。

初看一下,目前的代码结构如下图所示,在Content API之上,Chromium的WebView实现了封装一个新类AwContents,该类主要基于ContentViewCore类的实现。

AwContents提供的不是WebView的接口,所以,需要一层桥接部分,将AwContents桥接到WebView,这就是图15-2中的桥接模块,该模块位于Android源代码中,目前已经开源(Android 4.4代码树),开发者可以尝试自行编译。

图15-2 基于Chromium的WebView层次结构图

AwContents同样也是基于Content API开发的,在这点上,它同Content Shell和Chromium浏览器没有大的不同,区别在于它们对很多Content API接口中的回调类实现不同,这是Content API用于让使用者参与内部逻辑和实现的过程。具体来说,它主要有以下三个方面的不同。

  • 第一是渲染机制 :因为WebView提供的是一个View控件,那么View控件所在的容器可能需要该View控件将渲染结果保存在内存中(如位图),或者是保存在显存中(如Surface对象),所以,WebView需要提供两种不同的渲染输出结果。那么是否意味着WebView提供软件渲染和GPU硬件渲染两种方式呢?答案是否定的。目前,Chromium的Android版不提供网页软件渲染,只有GPU硬件渲染一种方式,其渲染的结果由合成器生成。那么,如何生成位图呢?最初是通过OpenGL图形库提供的回读(Readback)方式生成。当合成器每合成一帧的时候,AwContents类将该帧保存在一个存放在CPU内存中的链表中,当用户界面需要重新绘制的时候,便把当前的图片取出,绘制在当前控件的Canvas对象中。不过,这样做会导致其性能低效,所以这只是一个临时方案。在最新的代码中,Chromium即将引入一种新机制,能够支持输出到CPU内存中。
  • 第二是进程模型 :目前WebView只支持单进程方式,未来应该也不会支持多进程方式。单进程意味着没有办法使用Android的isolated UID机制,因此,某种程度上来讲,其安全性降低了,而且页面的渲染崩溃会导致使用WebView的应用程序崩溃。
  • 第三对系统库和内部接口的依赖 :目前Chromium WebView使用了Android系统的一些内部库,典型的如Skia图形库(通常系统中的Skia图形库版本较旧,性能没有最新的好),这使得性能方面存在某些问题。同时,Chromium WebView还依赖一些系统内部的接口,这些接口使得它不能用Android SDK和NDK来编译。
相关推荐
腾讯TNTWeb前端团队2 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰6 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪6 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪6 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy7 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom7 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom7 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom7 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom7 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom8 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试