Chromium WebUI机制介绍

本文简要介绍一些Chromium WebUI的特点,然后分析其内部机制,最后介绍如何创建使用WebUI。 WebUI介绍 WebUI是通过本地的html网页来实现客户端的UI功能,把c++、html、css、js组织在一起,css,html做界面,js和c++做逻辑,灵活而又强大。chromium UI里面很多地方使用WebUI ,比如设置页面,flags开关页面,关于页面。我们在浏览器的地址栏中输入chrome://chrome-urls/,就可以看到更多的WebUI 链接页面。 Chromium之所以大量用到WebUI,我想有两个主要原因: WebUI界面看起来就像是新建了一个tab打开的一个网页,UI交互非常统一,也非常简洁 利用html构建UI,减少了开发跨平台UI的复杂性 WebUI机制分析 我们现在以chromium中一个简单而又典型WebUI页面chrome://version/为例子分析WebUI机制。 创建WebUI流程 在地址栏中输入chrome://version/与输入一个网址创建新标签页的基本流程是一致的。在地址栏中输入任何网址WebContentsImpl都会创建WebUIImpl 。如果在GetWebUIFactoryFunction中找到对应的chrome::kChromeUIVersionHost,就会创建对应的WebUIController——VersionUI,然后WebContentsImpl::CreateWebUI会判断WebUIController是否创建成功,如果创建失败则销毁WebUIImpl。 资源加载流程 WebUI的资源加载也是复用一般的网页网络请求机制,不同的是一般的http协议底层是用URLRequestHttpJob去做网络请求,而WebUI则是使用URLRequestChromeJob。 在地址栏输入一个WebUI网址chrome://version/,就会创建VersionUI对象,VersionUI会创建一个与当前host绑定的WebUIDataSource,并添加到URLDataManager中。当发起网络请求,URLDataSourceImpl根据host返回对应的资源,然后再当做response返回。 类图介绍 ChromeWebUIControllerFactory是创建WebUI对应的WebUIController。 VersionUI实现了WebUIController,会根据WebUI的网址创建一个WebUIDataSource。WebUIDataSource就可以添加WebUI所需要的前端资源文件。VersionUI同时也创建VersionHandler并添加到WebUI中。 VersionHandler继承自WebUIMessageHandler。通过WebUI的RegisterMessageCallback来注册回调,VersionHandler就可以处理来自前端的js的调用。 其实VersionHandler并非必须要创建,任何类都可以通过WebUI来注册js回调函数。WebUI类就是用来连接js与c++交互的纽带。 c++与js交互 c++调用js非常简单,直接通过WebUI的CallJavascriptFunction来执行js代码中的函数,比如: CallJavascriptFunction底层其实是调用的通用的RenderFrameHost接口的ExecuteJavaScript。 Js调用c++稍微复杂一点。 首先browser进程中通过WebUI的RegisterMessageCallback来向js暴露自己可被调用的接口,实现对应接口处理函数。之后js就可以通过chrome.send方法去调用c++中的接口。 在renderer进程里面WebUIExtension::Install通过v8创建一个chrome的js对象,并暴露出send,getVariableValue两个接口,注册接口的c++回调函数。js直接调用chrome.send,然后在renderer进程中对应的回调函数通过IPC把函数调用相关的信息发送到browser进程中的WebUIImpl中。 前端资源 WebUI的前端html网页元素扩展了三个属性:i18n-content、i18n-options、i18n-values。 i18n-content可以用来指定元素的文本内容。比如我们在c++中指定application_label的字符串内容为Google Chrome,html网页写成<td class=”label” i18n-content=”application_label”></td>,最终渲染出的html为<td class=”label” i18n-content=”application_label”>Google Chrome</td>。 i18n-options会生成一个<select>的<option>元素,具体用法搜索现有代码中的例子。 i18n-values会生成一个元素的属性和值的列表。比如<html id=”t” i18n-values=”dir:textdirection;lang:language”>。 扩展属性中的值是c++把数据生成strings.js,然后网页再从strings.js中加载。 创建WebUI chromium有篇文档介绍如何创建WebUI界面。但这个文档有些过时,有些地方已经改变了。我们通过创建一个计算两个整数和的WebUI例子来学习如何使用WebUI。 在这个例子中,我们打开chrome://calculator/页面,会有两个输入框让我们输入两个整数,点击等号按钮,前端获取到输入的两个整数,然后调用c++的cpp_add函数计算出和,然后c++再调用js里面的set_result方法设置结果到输入框。 添加前端资源 WebUI的前端资源文件一般放在src/chrome/browser/resources目录下面,我们在这个目录下新增一个如下内容的calculator.html文件: c++代码在创建WebUIDataSource中可以指定这个标示符对应的字符串值。 最终chromium会渲染出html网页,其中就会把IDS_CALCULATOR_TITLE字符串的值根据calculator_title放到title里面,最终网页渲染出如下效果: 还有点注意的是html中引用了很多框架的js文件,其中load_time_data.js要放在最前面,i18n_template2.js要放在body里面。 然后再添加一个如下内容的calculator.js文件: 然后在src/chrome/app/generated_resources.grd加入一些本地化的字符串资源: 然后把新增前端文件加入到grd文件中,根据之前文件的惯例,我们加入到src/chrome/browser/browser_resources.grd文件中: 增加c++处理逻辑 增加url 首先,我们定义WebUI的url,在src/chrome/common/url_constants.h中定义: 然后在src/chrome/common/url_constants.cc中定义: 然后创建我们的WebUIController,我们定义CalculatorUI: 增加WebUI c++实现 CalculatorUI的实现如下: CalculatorUI会调用CreateCalculatorUIDataSource创建WebUIDataSource: 创建WebUIDataSource要跟指定的WebUI的host绑定到一起。AddLocalizedString是添加一些本地话字符串,AddString是添加ascii字符串,SetJsonPath是设置生成数据的js文件名。AddResourcePath是添加其他js资源,SetDefaultResource是添加html资源。 CalculatorUI也会在构造函数里增加WebUIMessageHandler类CalculatorHandler,在这个类里面处理c++与js的交互: 然后把新增的c++代码文件加入到src/chrome/chrome_browser_ui.gypi中: 最终效果 最后我们打开chrome://calculator/,在第一第二个输入输入数字,然后点击等号按钮,就会在第三个输入框里得到前面输入的两个数字的和。 ... Read More | Share it now!