1.CEF3使用多进程模式,Browser与Render分别处于两个独立进程之中;一般而言,Browser进程与我们的窗口进程一致,Render进程是一个独立的进程。
2.Browser进程和Render进程都包含browser和frame对象;
3.在CEF提供的例子中,主要是通过继承CefV8Handler,实现其
bool CefV8HandlerEx::Execute(const CefString &name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList &arguments,
CefRefPtr<CefV8Value> &retval,
CefString &exception)
方法来实现js对C++函数的调用。
如果这个函数调用是一个简单的调用,即当函数调用发生时,如果我们能够快速的返回结果,那么我们可以通过更改retval的值来返回函数调用结果。
因为这个函数调用是发生在Render进程中的,如果函数调用时,我们想获取Browser进程内的信息,那我们就需要通过进程间通讯(方式:调用Frame的SendProcessMessage(PID_Browser,msg))告诉Browser进程,但是此时的问题就是,进程间通讯是个异步操作,我们无法通过这个方式获得结果,所以会导致整个调用不再是连续的,因此js函数调用的结果将不可知,那该如何解决?
我们可以借助于js的异步调用来完成这一点,具体的思路如下:
1.js发起函数调用Func(需要注意这个Func是需要在Render_App的OnContextCreated方法中绑定到Context上,具体可参考https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md#markdown-header-window-binding,且有一个CefV8Handler与Func绑定),这个Func传递一个回调函数(callback)作为参数;
2.Render进程中的CefV8Handler的Execute检测到该函数,取得callback参数,将其放入到函数调用缓存中,可以参考https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-asynchronous-javascript-bindings
3.发送一个进程间消息告诉Browser进程,Browser进程需要实现OnProcessMessageReceived方法。Browser接受到该消息以后,完成相应的操作,并发送一个进程间消息告诉Render进程,Render进程同样也需要实现OnProcessMessageReceived方法;
4.Render进程接受到特定消息以后,检索出message中包含的参数信息,并从函数调用缓存中查找特定的callback函数;
5.当从在对应的callback时,调用该callback
6.js在Func中传递的callback中接收参数信息,并完成后续工作。
需要注意的是:
1.这个RenderApp进程,如果在加载的page中存在多个iframe,则这个OnContextCreated会被调用多次,如果不想再每个iframe中注册这个Func函数,则将其写入OnWebKitInitialed中,这个也是Render的一个接口。
2.如果存在多个iframe,并不在同一个域,则有可能会出现有些iframe无法接收消息的情况;
3.CefV8Handler最好实在RenderAPP的构造中初始化一次,不然在存在多个iframe的情况下,可能会出现函数缓存为空的情况,具体原因未知。