CEF和JS交互
Posted Tony
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CEF和JS交互相关的知识,希望对你有一定的参考价值。
CefClient提供所有浏览器事件处理的接口,重写CefClient类中的方法处理浏览器事件:包括Browser的生命周期,右键菜单,对话框,状态通知显示,下载事件,拖曳事件,焦点事件,键盘事件,离屏渲染事件等,对Cef进行行为控制的方法一般都集中在这些接口。
①
/*
注册浏览器生命周期的事件类CefLifeSpanHandler的实例。
重写CefLifeSpanHandler接口类中的方法实现对browser对象周期回调事件的处理:
*/
virtual CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() { return NULL;}
//当新browser对象被创建后马上触发,重写此方法保存所有创建的browser对象的指针。
void OnAfterCreated(CefRefPtr<CefBrowser> browser)
//当调用CloseBrowser函数后触发
bool DoClose(CefRefPtr<CefBrowser> browser)
//当browser对象被销毁前触发,必须重写此方法且完成释放对所有browser对象的指针。
void OnBeforeClose(CefRefPtr<CefBrowser> browser)
②
//当window render无法完成时采用离屏渲染,重写CefRenderHandler类中的方法实现离屏渲染回调事件的处理:
virtual CefRefPtr<CefRenderHandler> GetRenderHandler() { return NULL; }
//根窗口创建后触发,通过此接口可获取根窗口在屏幕的位置坐标。
bool GetRootScreenRect(CefRefPtr<CefBrowser> browser, CefRect& rect) { return false; }
//当browser对象初始化或者大小改变时触发,通过此接口获取browser对象在窗口的位置坐标。
bool GetViewRect(CefRefPtr<CefBrowser> browser, CefRect& rect)=0
③
virtual CefRefPtr<CefDisplayHandler> GetDisplayHandler() {return NULL;}
Browser对象显示状态的事件处理。
④
virtual CefRefPtr<CefJSDialogHandler> GetJSDialogHandler() { return NULL;}
与javascript dialogs相关的回调事件的处理,CefJSDialogHandler接口类中的方法在UI线程中调用。
⑤
virtual bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefProcessId source_process,CefRefPtr<CefProcessMessage> message) {return false;}
进程间通信接口,实现browser进程和render进程间的通信。当收到其他进程的消息时触发,当消息被处理后返回true。此回调函数外不可使用其他进程的消息或此消息的引用。
其他浏览器的回调事件(拖拽、下载、查找、焦点、键盘等)都在CefClient类中有对应的注册接口。
CefApp负责进程的实例化及退出。重写Cef类中的GetBrowserProcessHandler()及GetRenderProcessHandler()方法创建browser进程及render进程的实例。
CefBrowser及CefFrame为不可实例化的抽象类。其中,CefBrowser类表示一个浏览器窗口,CefFrame类表示浏览器窗口中的一块区域,一个浏览器窗口可包含多个Frame块。两者中的方法在browser进程中使用时一般可在所有线程中使用,在render进程中一般只能在主线程中使用。
启动Render进程:
1) 单一执行:browser主进程调用CefExcuteProcess()方法之后创建render子进程。分析CefExcuteProcess()方法的代码:首先根据命令行参数的type参数,如果为NULL,说明为主进程,返回-1,回到主程序,执行创建窗口等主进程代码。如果不为NULL,会在chrome代码里创建render进程。
2) 独立子进程执行:需要两个分开的工程和分开的入口函数。在主程序中的CefSettings settings中增加CefString(&settings.browser_subprocess_path)=子进程执行路径。
JS加载及与Cef的交互由Render进程处理,因此CefApp的GetRenderProcessHandler()方法必须提供实现,否则OnContextCreate()和OnWebktiInitialized()接口无法被调用。定义类继承自CefApp和CefRenderProcessHandler,重写CefApp中的GetRenderProcessHandler()方法并返回render进程实例的指针。CefRenderProcessHandler中的OnContextCreate()接口会在Frame的context创建后被调用,提供js与Cef代码交互的功能。
Cef基于Chrome,Chrome使用v8jsEngine执行内部的js。根据v8的规范,执行一段js代码必须显式指定context,因此在调用js代码的时候必须先进入context,而每一个Frame有属于自己的context,每一次Frame加载都会调用OnContextCreate()方法。
1) Cef调用JS:
Cef代码可以通过调用CefFrame::ExecuteJavaScript()方法执行js代码。
frame->ExecuteJavaScript(const CefString& jsCode,const CefString& frame->GetURL(), int startLine);
context所在的CefRefPtr<CefFrame> frame和CefRefPtr<CefBrowser> browser在OnContextCreate()接口中获取。
2) JS调用Cef
①重写OnContextCreate()方法,从OnContextCreate()接口提供的context中通过context-GetGlobal()获取window对象,window对象声明为cefV8Value类型(相当于js中所有对象和值都以var声明)。通过window-> SetValue(const CefString& key, CefRefPtr<CefV8Value> value, PropertyAttribute attribute)方法实现绑定该窗口对象下某一个CefV8Value类型对象(方法中参数value)和一特定标识符(方法中参数key)。
用来绑定的CefV8Value类型对象包含js基本数据类型(int,double,string,bool等)用CefV8Value::Create静态方法创建,例如string类型用CefV8Value::CreateString创建;以及js数组和对象类型,用静态方法CefV8Value::CreateArray()或CefV8Value::CreateObject ()创建。
②用来绑定的CefV8Value类型对象可以是函数对象定义一个类(例如MyCefV8Handler)继承自CefV8Handler,
利用
CefRefPtr<MyCefV8Handler> handler (new MyCefV8Handler());
CefV8Value func=CefV8Value::CreateFunction(const CefString& name, CefRefPtr<CefV8Handler> handler) 方法创建函数对象并调用window-> SetValue()进行绑定。CreateFunction传入的参数为函数名和实例化的MyCefV8Handler对象,并且在MyCefV8Handler类中必须重写CefV8Handler中的Execute()方法判断js调用的Cef方法并接收参数及传递返回值。
JS调用Cef中的方法示例代码:
//自定义SimRender类继承CefApp类和CefRenderProcessHandler类
class simpleRender :public CefApp, public CefRenderProcessHandler
{
public:
//重写GetRenderProcessHandler方法,render进程启动时被唤醒来创建render进程的示例
void CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() OVERRIDE
{
return this;
}
//重写OnContextCreated方法,每一次Frame加载都会调用OnContextCreate()方法,绑定window对象
void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) OVERRIDE
{
//获取window对象
CefRefPtr<CefV8Value> window = context->GetGlobal();
//创建MyCefV8Handler对象实例
CefRefPtr<MyCefV8Handler> handler(new MyCefV8Handler());
//创建函数对象myFunc
CefRefPtr<CefV8Value> myFunc = CefV8Value::CreateFunction(_T("func"), handler);
//绑定函数对象myFunc和以标识符“func”,js通过window.func调用Cef代码
window->SetValue(_T("func"), myFunc, V8_PROPERTY_ATTRIBUTE_NONE);
}
}
//自定义MyCefV8Handler类继承CefV8Handler类
class MyCefV8Handler :public CefV8Handler
{
public:
//重写Execute方法判断js调用的Cef方法
bool Execute(const CefString& func_name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception)
{
if (func_name == _T("func"))
{
retval = CefV8Value::CreateString(_T("func: C++!"));
return true;
}
return false;
}
}
js中:
<script type="text/javascript">
Function f()
{
var retval=window.func();
window.alert(retval);
}
</script>
以上是关于CEF和JS交互的主要内容,如果未能解决你的问题,请参考以下文章
Linux + Qt : QWebEngineView + QWebChannel 与 JS 交互传递信息
使用CefSharp在.Net程序中嵌入Chrome浏览器——Javascript交互