chromium之WebUI
Chromium WebUI机制介绍
WebUI机制的几个部分
1.WebUI类,主要作用:
(1)从render进程接收js调用发来的消息,执行相应的C++函数;
(2)提供执行js代码的接口;2.WebUIController类, 主要作用:
(1)控制WebUI页面的行为;
(2)为WebUI页面管理数据源和消息处理器;3.WebUIDataSource类,主要作用:
为WebUI页面提供各种资源,例如需要加载的HTML文件、css以及js文件,同时还包括png图片资源,本地化的字符串资源。
4.主要结构如下图(图有点丑):
Js调用
在RenderFrame创建的时候,chromium向V8中注册了两个函数,作用是Js调用WebUI的函数以及获取WebUI处理结束之后的结果,如下:
v8::Local<v8::Object> chrome = GetOrCreateChromeObject(isolate,context->Global()); chrome->Set(gin::StringToSymbol(isolate, "send"),gin::CreateFunctionTemplate(isolate, base::Bind(&WebUIExtension::Send))->GetFunction()); chrome->Set(gin::StringToSymbol(isolate, "getVariableValue"),gin::CreateFunctionTemplate(isolate, base::Bind(&WebUIExtension::GetVariableValue))->GetFunction());
主要使用的就是send,js代码通过调用send(),将参数打包然后调用此处的绑定的WebUIExtension::Send()方法,Send()方法中获取当前页面对应的RenderView,然后由RenderView将参数通过IPC发送到Browser端,由WebUI来处理。 细节可参见WebUIExtension::Send()方法的实现。
WebUI工作流程
WebUI创建过程
WebUI的创建流程如下:
1.在加载url时,由WebContents来创建一个WebUI对象;
WebUI* WebContentsImpl::CreateWebUI(const GURL& url,const std::string& frame_name) {WebUIImpl* web_ui = new WebUIImpl(this, frame_name);WebUIController* controller = WebUIControllerFactoryRegistry::GetInstance()->CreateWebUIControllerForURL(web_ui, url);if (controller) {web_ui->AddMessageHandler(new GenericHandler());web_ui->SetController(controller);return web_ui;}delete web_ui;return NULL; }
以上代码中,首先创建一个WebUI对象,然后再创建WebUIContoller对象,若controller对象创建成功,则将其绑定到WebUI对象中,由WebUI来管理;否则,销毁WebUI对象。
在WebUIController创建时会初始化WebUI中的数据源,这部分在《WebUI资源初始化.md》中。
注册处理函数
在WebUIController(controller)创建时,除了数据源的初始化,还需要向WebUI中注册js调用要执行的函数,调用的WebUI中的方法,如下:
// WebUIImpl中的定义 void WebUIImpl::RegisterMessageCallback(const std::string& message, const MessageCallback& callback) {message_callbacks_.insert(std::make_pair(message, callback)); }// 具体的调用通常在controller的构造或者初始化函数中 web_ui->RegisterMessageCallback("queryHistory",base::Bind(&HistoryUI::HandleQueryHistory,base::Unretained(this)));
以上的调用时OB History页面中的注册查询history的方法,HandleQueryHistory方法就是由开发者实现的方法。”queryHistory”这个字符串同时也是js调用传来的消息的第一个参数。
在WebUIImpl中,OnMessageReceived()方法接收到信息之后,就通过消息的第一个参数,在message_callback_中查询对应的回调函数,然后执行这个回调函数,如下:bool WebUIImpl::OnMessageReceived(const IPC::Message& message) {bool handled = true;IPC_BEGIN_MESSAGE_MAP(WebUIImpl, message)IPC_MESSAGE_HANDLER(ViewHostMsg_WebUISend, OnWebUISend)IPC_MESSAGE_UNHANDLED(handled = false)IPC_END_MESSAGE_MAP()return handled; }void WebUIImpl::OnWebUISend(const GURL& source_url,const std::string& message,const base::ListValue& args) {// 略去部分代码...ProcessWebUIMessage(source_url, message, args); }void WebUIImpl::ProcessWebUIMessage(const GURL& source_url,const std::string& message,const base::ListValue& args) {if (controller_->OverrideHandleWebUIMessage(source_url, message, args))return;// Look up the callback for this message.MessageCallbackMap::const_iterator callback = message_callbacks_.find(message);if (callback != message_callbacks_.end()) {// Forward this message and content on.callback->second.Run(&args);} else {NOTREACHED() << "Unhandled chrome.send(\"" << message << "\");";} }
以上代码就是从WebUI在OnMessageReceived()中接收到消息之后,一直到执行绑定的回调函数的过程。值得注意的是在ProcessWebUIMessage()中,若想让controller直接处理消息,就重载WebUIController中的OverrideHandleWebUIMessage()方法,处理结束返回true即可,此处默认方法返回是false。
问题:
1.在我们OB的history页面中使用了注册的方式来执行回调函数。但是controller也有OverrideHandleWebUIMessage()方法,为什么不用这个方法呢?2.chromium中的callback是一个闭包,包含了一个函数执行的环境,其封装原理值得学习。
执行Js代码
WebUI中同样提供了执行Js代码的接口
JavaScript代码向上的调用流程:
1.首先调用WebUI中的CallJavaScript()系列方法,这个函数有几个同类函数,区别就是参数数量不一样,传入js函数名以及参数,这个是WebUI中调用js的入口函数,如下:
void WebUIImpl::CallJavascriptFunction( const std::string& function_name, const base::Value& arg1, const base::Value& arg2) {DCHECK(base::IsStringASCII(function_name));std::vector<const base::Value*> args;args.push_back(&arg1);args.push_back(&arg2);ExecuteJavascript(GetJavascriptCall(function_name, args)); }
上面这个函数,参数个数是2个,参数数量为1~4时,都采用上述方法;如果不带参数,调用时只需要传入函数名,也用不着vector,当参数个数大于4个时,需要调用者自己将参数存进一个vector中,将vector作为参数传进来。
以上函数中有个GetJavaScriptCall()函数,其作用很简单,将函数与参数连接起来,组成一个字符串。
2.然后看看上面调用ExecuteJavascript()方法,参数就是以上组成的字符串,其中获取当前的RenderFrameHost;
void WebUIImpl::ExecuteJavascript(const base::string16& javascript) {RenderFrameHost* target_frame = TargetFrame();if (target_frame) {if (!(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(target_frame->GetProcess()->GetID()) ||// It's possible to load about:blank in a Web UI renderer.// See http://crbug.com/42547target_frame->GetLastCommittedURL().spec() == url::kAboutBlankURL)) {// Don't crash when we try to inject JavaScript into a non-WebUI page, but// upload a crash report anyways. http://crbug.com/516690base::debug::DumpWithoutCrashing();return;}target_frame->ExecuteJavaScript(javascript);} }
3.调用RenderFrameHost的ExecuteJavascript()方法,将javascript语句打包进IPC消息中,向RenderFrame发送IPC消息FrameMsg_JavaScriptExecuteRequest;
void RenderFrameHostImpl::ExecuteJavaScript(const base::string16& javascript) {CHECK(CanExecuteJavaScript());Send(new FrameMsg_JavaScriptExecuteRequest(routing_id_,javascript,0, false)); }
通过routing_id来确定由哪个frame来接受哦这个消息,消息中的第三个参数表示在执行js之后是否需要返回结果,若要会返回结果,需要调用另外一个函数,并传入一个回到函数,具体参见render_frame_host_impl.cc。
4.RenderFrame收到IPC消息后,将调用WebLocalFrame的函数executeScriptAndReturnValue()方法,传入js语句,如下;
bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {...IPC_MESSAGE_HANDLER(FrameMsg_JavaScriptExecuteRequest,OnJavaScriptExecuteRequest)... }void RenderFrameImpl::OnJavaScriptExecuteRequest(const base::string16& jscript,int id,bool notify_result) {TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequest",TRACE_EVENT_SCOPE_THREAD);v8::HandleScope handle_scope(v8::Isolate::GetCurrent());v8::Local<v8::Value> result =frame_->executeScriptAndReturnValue(WebScriptSource(jscript));HandleJavascriptExecutionResult(jscript, id, notify_result, result); }
以上是RenderFrameImpl中的处理,最有一行的HandleJavaScriptExecutionResult()方法就是是否返回结果的实现。
5.RenderFrameImplement中,再往下就是Webkit里面的调用:
WebLocalFrame通过LocalFrame中的script()方法,得到ScriptController,调用Controller的executeScriptInMainWorldAndReturnValue()来执行js语句,并返回结果。最终是调用v8Call()方法来执行语句。具体可参见ScriptController.cpp
结语
本文档主要介绍了Chromium WebUI作用及工作流程(browser <==> render):
1.WebUI机制就是用来显示本地页面,其中WebUI负责所有对象(controller对象,handler对象等)的管理,同时也是js与C++相互调用的桥梁;
2.WebUIController负责主要的逻辑处理,具体处理js向C++的调用以及js调用的发起,同时还管理数据类WebUIDataSource。
3.WebUIDataSource就是提供数据源,是显示页面的时候,所有数据的提供者。
chromium之WebUI相关推荐
- chromium - DISALLOW_IMPLICIT_CONSTRUCTORS
前言 在看内建web-ui实现时,总能看到类后面有个宏 DISALLOW_COPY_AND_ASSIGN 以前忙着别的,没追究.今天做了c++11的default和delete语法的实验,明白这些宏的 ...
- 定制化chromium的修改方法
由于chromium的代码量很大,且版本也是更新较快,很难短时间内消化吸收,主要方法:通过 cs.chromium.org 来查找关键字,修改完成后需要整体编译. 本次修改大都是按照版本62.0.32 ...
- 为什么要用webUI?
先看看身边有哪些软件已经在用webUI: 1.QQ查找窗口: 2.LOL主界面: 3.EC营销软件功能界面: 三个例子足以说明一切: 1.HTML是目前在用户体验.界面舒适度最先进的语言 2.HTML ...
- 搭建webUI自动化及问题解决:Message: ‘chromedriver‘ executable needs to be in PATH.解决办法
搭建webUI自动化环境 1.conda install selenium即可. 若出现:Message: 'chromedriver' executable needs to be in PATH. ...
- chromium aura简介
Aura 目的 Aura是为了创建一个全新的桌面窗口管理系统,通过硬件加速提供绚丽的UI效果. UI设计 一个视图层级依附于一个widget,widget是一个跨平台类型,依赖于NativeWidge ...
- chromium摘抄
网上介绍chromium知识的文章挺多,省的自己写了,在这里就直接摘录一下 1.WwebUI WebUI就是chrome://xxx/所显示的页面,WebUI也提供了一些新的api. 学习WebUI的 ...
- Chromium浏览器(CEF)的命令行列表说明
找到的Chromium浏览器的命令行说明列表,转放在这里以方便查看. List of Chromium Command Line Switches There are lots of command ...
- Chromium命令行开关列表2
Chromium命令行开关列表 Google Chrome浏览器可以使用很多命令行. 一些更改功能的行为,其他用于调试或试验. 该页面列出了可用的开关,包括其条件和说明. 上一次自动更新发生在2020 ...
- chromium gn parameter list
前言 查资料时,看到如何看gn都提供什么参数列表了. 这样,编译chromium工程时,可以编译的更精细. 实验 可以将参数写到 Z:\chromium\src\out\my_x86_d\args.g ...
- centos 安装 aria2 webui 实现网页下载
centos aria2 webui 安装aria2 安装 rpmforge源 wget http://repository.it4i.cz/mirrors/repoforge/redhat/el6/ ...
最新文章
- Windows Azure Pack集成配置SPF
- postman怎么传session_十几行代码实现分布式 Session
- 需要注意变量作用域的使用
- java位运算实例详解——(amp;)、(|)、(~)、(^)、(lt;lt;)、(gt;gt;)
- 宝塔面板网站一打开cpu百分百_BT宝塔面板打开这个功能网站快到起飞,降低宝塔面板内存和CPU使用率,降低运行负载...
- 关于 Mac OS X 内核技术来源
- python高级特性:迭代器与生成器
- Windows Win7建立wifi热点,手机共享WIFI上网
- Slowquery图形化显示MySQL慢日志工具搭建
- nginx tcp转发_Nginx性能优化技巧
- CSS3 -- display:flex
- 用Julia学习微积分:这有一份高赞数学教程 | 附习题+代码
- EF架构~为ObjectContext类型加个Find方法
- 通讯(transport)
- css中引入下载字体的方法
- Ffmpeg常用转码命令
- 联想台式电脑一键恢复后桌面没有计算机了,联想笔记本一键恢复功能使用教程...
- 信号处理之FIR数字滤波器(Matlab仿真)
- 这是一篇能够教会你运营阿里巴巴国际站的文章
- 2022电工(初级)上岗证题目及答案
热门文章
- AMD处理器与INTEL的区别
- 打开Excel2010时提示错误:向程序发送命令时出现问题!
- php 调用mp3,使用PHP合并MP3文件的类,兼容php4、php5(2)
- linux系统触摸板双击,在Ubuntu 18.04系统中搞定触摸板多点触控
- Dubbo本地存根是什么,Dubbo本地伪装又是什么?
- 设置Windows Server登录时禁止自动启动服务器管理器
- PHP压缩文件下载,提示压缩包损坏及打不开的解决方法
- java常用英语单词大全
- 史玉柱自述:我是怎么带队伍的
- 微信公众号访问 ssm框架根目录下MP_verify_xxxxxx.txt的解决方法