CEF JS与browser进程间的异步通信

时间:2024-04-08 11:31:04
                     

基于CEF开发时经常需要在JS和C++代码间通信,我们在CEF中JavaScript与C++交互中讨论了常见的交互方式,不过都是在Renderer进程中,这次来看看如何在JS和Browser进程间通信,基本介绍可以看这里:
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-asynchronous-javascript-bindings

具体做法,上面给出的链接里有大概说明,另外在cef_message_router.h中有详细说明,它分了9步,有需要的可以去查看。我试验了下可行。按照我的实验,从三个方面来说说:

  • browser进程
  • renderer进程
  • html中的js
 

foruok原创,转载请关注微信订阅号“程序视界”联系foruok。

browser进程

  • 1)配置browser进程这一侧的Message Router

使用CefMessageRouterConfig来定义可以在html中使用的方法名字。代码片段可能如下:

...CefMessageRouterConfig g_messageRouterConfig;int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,                     _In_opt_ HINSTANCE hPrevInstance,                     _In_ LPTSTR    lpCmdLine,                     _In_ int       nCmdShow){    UNREFERENCED_PARAMETER(hPrevInstance);    UNREFERENCED_PARAMETER(lpCmdLine);    // Enable High-DPI support on Windows 7 or newer.    CefEnableHighDPISupport();    g_messageRouterConfig.js_query_function = "cefQuery";    g_messageRouterConfig.js_cancel_function = "cefQueryCancel";    CefMainArgs main_args(hInstance);    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

注意我在main函数之外定义了一个CefMessageRouterConfig的实例,然后在main函数中设置了query和cancel这两个函数。它们定义了可以在html的js代码里使用的方法,比如根据上面代码,你可以用window.cefQuery({…})。

  • 2)创建CefMessageRouterBrowserSide的实例

browser进程这边需要一个CefMessageRouterBrowserSide的实例来处理renderer进程发过来的消息。建议把这个实例作为成员变量放在CefClient的派生类中,因为它CefMessageRouterBrowserSide定义了一些方法,需要在指定的地方调用。

声明和初始化的代码片段:

CefRefPtr<CefMessageRouterBrowserSide> m_browser_side_router;...extern CefMessageRouterConfig g_messageRouterConfig;m_browser_side_router = CefMessageRouterBrowserSide::Create(g_messageRouterConfig);...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 3)调用预定义方法

CefMessageRouterBrowserSide预定义了下列接口,需要在指定地方调用:

// call from CefClient::OnProcessMessageReceivedbool OnProcessMessageReceived(...)// call from CefLifeSpanHandler::OnBeforeClose()void OnBeforeClose(CefRefPtr<CefBrowser> browser)// call from CefRequestHandler::OnRenderProcessTerminated()void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser)// call from CefRequestHandler::OnBeforeBrowse()void OnBeforeBrowse(...)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

所以,我们的这个ClientHandler类,声明如下:

class ClientHandler : public CefClient,    public CefDisplayHandler,    public CefLifeSpanHandler,    public CefLoadHandler,    public CefRequestHandler{    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

ClientHandler要实现CefClient的OnProcessMessageReceived、CefLifeSpanHandler的OnBeforeClose、CefRequestHandler的OnRenderProcessTerminated和OnBeforeBrowse方法,在这些方法里调用CefMessageRouterBrowserSide的同名方法即可。代码片段如下:

void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser){    CEF_REQUIRE_UI_THREAD();    m_browser_side_router->OnBeforeClose(browser);    ...}bool ClientHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,    CefProcessId source_process,    CefRefPtr<CefProcessMessage> message){    if (m_browser_side_router->OnProcessMessageReceived(browser, source_process, message)) return true;    return false;}bool ClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, bool is_redirect){    m_browser_side_router->OnBeforeBrowse(browser, frame);    return false;}void ClientHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser, TerminationStatus status){    m_browser_side_router->OnRenderProcessTerminated(browser);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 4) 在browser进程里实现处理JS查询的handler

CefMessageRouterBrowserSide定义了一个内部类Handler,继承它:

class BrowserSideJSHandler : public CefMessageRouterBrowserSide::Handler{public:    BrowserSideJSHandler();    virtual bool OnQuery(CefRefPtr<CefBrowser> browser,        CefRefPtr<CefFrame> frame,        int64 query_id,        const CefString& request,        bool persistent,        CefRefPtr<Callback> callback);    virtual void OnQueryCanceled(CefRefPtr<CefBrowser> browser,        CefRefPtr<CefFrame> frame,        int64 query_id);};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

实现 OnQuery 和 OnQueryCanceled两个方法:

bool BrowserSideJSHandler::OnQuery(CefRefPtr<CefBrowser> browser,     CefRefPtr<CefFrame> frame, int64 query_id,     const CefString& request, bool persistent, CefRefPtr<Callback> callback){    if (request == "HelloCefQuery")    {        callback->Success("HelloCefQuery Ok");        return true;    }    else if (request == "GiveMeMoney")    {        callback->Failure(404, "There are none thus query!");        return true;    }    return false; // give other handler chance}void BrowserSideJSHandler::OnQueryCanceled(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int64 query_id){    //cancel our async query task...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 5)给CefMessageRouterBrowserSide的实例添加handler

我在ClientHandler类中定义了一个BrowserSideJSHandler的实例,类似下面:

class ClientHandler : public CefClient,    public CefDisplayHandler,    public CefLifeSpanHandler,    public CefLoadHandler,    public CefRequestHandler{    ...    CefRefPtr<CefMessageRouterBrowserSide> m_browser_side_router;    BrowserSideJSHandler m_jsHandler;    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后在ClientHandler构造函数中加入了下列代码:

m_browser_side_router->AddHandler(&m_jsHandler, true);
  • 1

上面的代码把BrowserSideJSHandler加入到browser进程里的消息路由器中。

好了,到这里browser进程配置完成。接下来看renderer进程。

renderer进程

  • 1)配置renderer进程这一侧的Message Router

renderer进程的配置和browser必须一致!

因为我browser和renderer使用一个进程,所以前面的代码可以共用,不说了。

  • 2)创建CefMessageRouterRendererSide的实例

renderer进程这边需要一个CefMessageRouterRendererSide的实例来处理browser进程发过来的消息和js传入的信息。建议把这个实例作为成员变量放在CefApp的派生类中。

我的定义类似下面:

class ClientAppRenderer : public CefApp,    public CefRenderProcessHandler {    ...    CefRefPtr<CefMessageRouterRendererSide> m_renderer_side_router;    ...};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

创建类似下面:

m_renderer_side_router = CefMessageRouterRendererSide::Create(g_messageRouterConfig);
  • 1
  • 3) 调用预定义方法

CefMessageRouterRendererSide定义了下面三个预定义方法:

void OnContextCreated(...)void OnContextReleased(...)bool OnProcessMessageReceived(...)
  • 1
  • 2
  • 3

这三个方法需要在CefRenderProcessHandler的派生类的同名方法里调用,我的代码片段:

void ClientAppRenderer::OnContextCreated(CefRefPtr<CefBrowser> browser,    CefRefPtr<CefFrame> frame,    CefRefPtr<CefV8Context> context){    m_renderer_side_router->OnContextCreated(browser, frame, context);}void ClientAppRenderer::OnContextReleased(CefRefPtr<CefBrowser> browser,     CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context){    m_renderer_side_router->OnContextReleased(browser, frame, context);}bool ClientAppRenderer::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,    CefProcessId source_process,    CefRefPtr<CefProcessMessage> message){    if (m_renderer_side_router->OnProcessMessageReceived(browser, source_process, message)) return true;    return false;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

好啦,renderer进程这边的事儿干完了。接下来就可以在html里写js代码调用cefQuery方法了。

html中的js

html这一侧很简单,我的测试代码如下:

<!DOCTYPE html><html>  <!--  Copyright (c) 2016 [email protected]微信订阅号“程序视界”(programmer_sight).   All rights reserved.  Use of this source code is governed by a BSD-style license that can be  found in the LICENSE file.  --><head>    <script type="text/javascript">      function doQuery() {        window.cefQuery({          request: document.getElementById("query").value,          persistent: false,          onSuccess: function(response) { alert(response); },          onFailure: function(code, msg) { alert(code + " - " + msg); }        }        );      }    </script>  <meta charset="UTF-8">  <title>Test Cef Query</title></head><body><form>Query String: <input type="text" id="query" value="HelloCefQuery"/>&nbsp;&nbsp;<input  type="button" value="SendQuery" onclick="doQuery()"/></form></body></html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

关键的代码起始就一个函数:

function doQuery() {        window.cefQuery({          request: document.getElementById("query").value,          persistent: false,          onSuccess: function(response) { alert(response); },          onFailure: function(code, msg) { alert(code + " - " + msg); }        }    );}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

cefQuery方法接受一个JS对象,如你所见,request、persistent可以对应到BrowserSideJSHandler::OnQuery的参数上,onSuccess和onFailure则在renderer进程里做了转换,到browser进程里对应到了CefMessageRouterBrowserSide::Callback的Success和Failure方法上。

我的实现,对HelloCefQuery调用success,对GiveMeMoney调用failure,其它的都没处理。

成功时的效果:

CEF JS与browser进程间的异步通信

失败时的效果:

CEF JS与browser进程间的异步通信

查询未被处理时的效果:

CEF JS与browser进程间的异步通信

Cef Generic Message Router的实现

Generic Message Router内部实现有两个关键点:

  1. CefMessageRouterRendererSide在renderer进程内,在OnContextCreated中向JS导出了cefQuery和cefQueryCancel两个方法,具体见cef_message_router.cc
  2. renderer和browser进程间使用SendProcessMessage通信,在OnProcessMessageReceived中处理消息

就这样吧。

其他参考文章详见我的专栏:【CEF与PPAPI开发】。

           

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

                     

基于CEF开发时经常需要在JS和C++代码间通信,我们在CEF中JavaScript与C++交互中讨论了常见的交互方式,不过都是在Renderer进程中,这次来看看如何在JS和Browser进程间通信,基本介绍可以看这里:
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-asynchronous-javascript-bindings

具体做法,上面给出的链接里有大概说明,另外在cef_message_router.h中有详细说明,它分了9步,有需要的可以去查看。我试验了下可行。按照我的实验,从三个方面来说说:

  • browser进程
  • renderer进程
  • html中的js
 

foruok原创,转载请关注微信订阅号“程序视界”联系foruok。

browser进程

  • 1)配置browser进程这一侧的Message Router

使用CefMessageRouterConfig来定义可以在html中使用的方法名字。代码片段可能如下:

...CefMessageRouterConfig g_messageRouterConfig;int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,                     _In_opt_ HINSTANCE hPrevInstance,                     _In_ LPTSTR    lpCmdLine,                     _In_ int       nCmdShow){    UNREFERENCED_PARAMETER(hPrevInstance);    UNREFERENCED_PARAMETER(lpCmdLine);    // Enable High-DPI support on Windows 7 or newer.    CefEnableHighDPISupport();    g_messageRouterConfig.js_query_function = "cefQuery";    g_messageRouterConfig.js_cancel_function = "cefQueryCancel";    CefMainArgs main_args(hInstance);    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

注意我在main函数之外定义了一个CefMessageRouterConfig的实例,然后在main函数中设置了query和cancel这两个函数。它们定义了可以在html的js代码里使用的方法,比如根据上面代码,你可以用window.cefQuery({…})。

  • 2)创建CefMessageRouterBrowserSide的实例

browser进程这边需要一个CefMessageRouterBrowserSide的实例来处理renderer进程发过来的消息。建议把这个实例作为成员变量放在CefClient的派生类中,因为它CefMessageRouterBrowserSide定义了一些方法,需要在指定的地方调用。

声明和初始化的代码片段:

CefRefPtr<CefMessageRouterBrowserSide> m_browser_side_router;...extern CefMessageRouterConfig g_messageRouterConfig;m_browser_side_router = CefMessageRouterBrowserSide::Create(g_messageRouterConfig);...
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 3)调用预定义方法

CefMessageRouterBrowserSide预定义了下列接口,需要在指定地方调用:

// call from CefClient::OnProcessMessageReceivedbool OnProcessMessageReceived(...)// call from CefLifeSpanHandler::OnBeforeClose()void OnBeforeClose(CefRefPtr<CefBrowser> browser)// call from CefRequestHandler::OnRenderProcessTerminated()void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser)// call from CefRequestHandler::OnBeforeBrowse()void OnBeforeBrowse(...)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

所以,我们的这个ClientHandler类,声明如下:

class ClientHandler : public CefClient,    public CefDisplayHandler,    public CefLifeSpanHandler,    public CefLoadHandler,    public CefRequestHandler{    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

ClientHandler要实现CefClient的OnProcessMessageReceived、CefLifeSpanHandler的OnBeforeClose、CefRequestHandler的OnRenderProcessTerminated和OnBeforeBrowse方法,在这些方法里调用CefMessageRouterBrowserSide的同名方法即可。代码片段如下:

void ClientHandler::OnBeforeClose(CefRefPtr<CefBrowser> browser){    CEF_REQUIRE_UI_THREAD();    m_browser_side_router->OnBeforeClose(browser);    ...}bool ClientHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,    CefProcessId source_process,    CefRefPtr<CefProcessMessage> message){    if (m_browser_side_router->OnProcessMessageReceived(browser, source_process, message)) return true;    return false;}bool ClientHandler::OnBeforeBrowse(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, bool is_redirect){    m_browser_side_router->OnBeforeBrowse(browser, frame);    return false;}void ClientHandler::OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser, TerminationStatus status){    m_browser_side_router->OnRenderProcessTerminated(browser);}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 4) 在browser进程里实现处理JS查询的handler

CefMessageRouterBrowserSide定义了一个内部类Handler,继承它:

class BrowserSideJSHandler : public CefMessageRouterBrowserSide::Handler{public:    BrowserSideJSHandler();    virtual bool OnQuery(CefRefPtr<CefBrowser> browser,        CefRefPtr<CefFrame> frame,        int64 query_id,        const CefString& request,        bool persistent,        CefRefPtr<Callback> callback);    virtual void OnQueryCanceled(CefRefPtr<CefBrowser> browser,        CefRefPtr<CefFrame> frame,        int64 query_id);};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

实现 OnQuery 和 OnQueryCanceled两个方法:

bool BrowserSideJSHandler::OnQuery(CefRefPtr<CefBrowser> browser,     CefRefPtr<CefFrame> frame, int64 query_id,     const CefString& request, bool persistent, CefRefPtr<Callback> callback){    if (request == "HelloCefQuery")    {        callback->Success("HelloCefQuery Ok");        return true;    }    else if (request == "GiveMeMoney")    {        callback->Failure(404, "There are none thus query!");        return true;    }    return false; // give other handler chance}void BrowserSideJSHandler::OnQueryCanceled(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int64 query_id){    //cancel our async query task...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 5)给CefMessageRouterBrowserSide的实例添加handler

我在ClientHandler类中定义了一个BrowserSideJSHandler的实例,类似下面:

class ClientHandler : public CefClient,    public CefDisplayHandler,    public CefLifeSpanHandler,    public CefLoadHandler,    public CefRequestHandler{    ...    CefRefPtr<CefMessageRouterBrowserSide> m_browser_side_router;    BrowserSideJSHandler m_jsHandler;    ...}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

然后在ClientHandler构造函数中加入了下列代码:

m_browser_side_router->AddHandler(&m_jsHandler, true);
  • 1

上面的代码把BrowserSideJSHandler加入到browser进程里的消息路由器中。

好了,到这里browser进程配置完成。接下来看renderer进程。

renderer进程

  • 1)配置renderer进程这一侧的Message Router

renderer进程的配置和browser必须一致!

因为我browser和renderer使用一个进程,所以前面的代码可以共用,不说了。

  • 2)创建CefMessageRouterRendererSide的实例

renderer进程这边需要一个CefMessageRouterRendererSide的实例来处理browser进程发过来的消息和js传入的信息。建议把这个实例作为成员变量放在CefApp的派生类中。

我的定义类似下面:

class ClientAppRenderer : public CefApp,    public CefRenderProcessHandler {    ...    CefRefPtr<CefMessageRouterRendererSide> m_renderer_side_router;    ...};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

创建类似下面:

m_renderer_side_router = CefMessageRouterRendererSide::Create(g_messageRouterConfig);
  • 1
  • 3) 调用预定义方法

CefMessageRouterRendererSide定义了下面三个预定义方法:

void OnContextCreated(...)void OnContextReleased(...)bool OnProcessMessageReceived(...)
  • 1
  • 2
  • 3

这三个方法需要在CefRenderProcessHandler的派生类的同名方法里调用,我的代码片段:

void ClientAppRenderer::OnContextCreated(CefRefPtr<CefBrowser> browser,    CefRefPtr<CefFrame> frame,    CefRefPtr<CefV8Context> context){    m_renderer_side_router->OnContextCreated(browser, frame, context);}void ClientAppRenderer::OnContextReleased(CefRefPtr<CefBrowser> browser,     CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context){    m_renderer_side_router->OnContextReleased(browser, frame, context);}bool ClientAppRenderer::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,    CefProcessId source_process,    CefRefPtr<CefProcessMessage> message){    if (m_renderer_side_router->OnProcessMessageReceived(browser, source_process, message)) return true;    return false;}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

好啦,renderer进程这边的事儿干完了。接下来就可以在html里写js代码调用cefQuery方法了。

html中的js

html这一侧很简单,我的测试代码如下:

<!DOCTYPE html><html>  <!--  Copyright (c) 2016 [email protected]微信订阅号“程序视界”(programmer_sight).   All rights reserved.  Use of this source code is governed by a BSD-style license that can be  found in the LICENSE file.  --><head>    <script type="text/javascript">      function doQuery() {        window.cefQuery({          request: document.getElementById("query").value,          persistent: false,          onSuccess: function(response) { alert(response); },          onFailure: function(code, msg) { alert(code + " - " + msg); }        }        );      }    </script>  <meta charset="UTF-8">  <title>Test Cef Query</title></head><body><form>Query String: <input type="text" id="query" value="HelloCefQuery"/>&nbsp;&nbsp;<input  type="button" value="SendQuery" onclick="doQuery()"/></form></body></html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

关键的代码起始就一个函数:

function doQuery() {        window.cefQuery({          request: document.getElementById("query").value,          persistent: false,          onSuccess: function(response) { alert(response); },          onFailure: function(code, msg) { alert(code + " - " + msg); }        }    );}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

cefQuery方法接受一个JS对象,如你所见,request、persistent可以对应到BrowserSideJSHandler::OnQuery的参数上,onSuccess和onFailure则在renderer进程里做了转换,到browser进程里对应到了CefMessageRouterBrowserSide::Callback的Success和Failure方法上。

我的实现,对HelloCefQuery调用success,对GiveMeMoney调用failure,其它的都没处理。

成功时的效果:

CEF JS与browser进程间的异步通信

失败时的效果:

CEF JS与browser进程间的异步通信

查询未被处理时的效果:

CEF JS与browser进程间的异步通信

Cef Generic Message Router的实现

Generic Message Router内部实现有两个关键点:

  1. CefMessageRouterRendererSide在renderer进程内,在OnContextCreated中向JS导出了cefQuery和cefQueryCancel两个方法,具体见cef_message_router.cc
  2. renderer和browser进程间使用SendProcessMessage通信,在OnProcessMessageReceived中处理消息

就这样吧。

其他参考文章详见我的专栏:【CEF与PPAPI开发】。