CEF中Browser进程与Render进程间通信

Posted foruok

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CEF中Browser进程与Render进程间通信相关的知识,希望对你有一定的参考价值。

https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage提到了CEF提供的Browser与Browser进程通信的几种机制,我实验了Process Runtime Messages这种方式,用到了CefProcessMessage和CefBrowser::SendProcessMessage()。

我是在CEF中JS与C++交互一文的基础上完成的,我们边说基本步骤,边给出关键代码。

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

    1. 发送消息

发送消息使用CefBrowser::SendProcessMessage() ,SendProcessMessage第一个参数是CefProcessId,给Browser进程发送,就用PID_BROWSER,给Render进程发送,就用PID_RENDERER。

我在Render进程发送消息的代码如下(ClientV8Handler的Execute方法内):

        CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create("login_msg");

        // Retrieve the argument list object.
        CefRefPtr<CefListValue> args = msg->GetArgumentList();

        // Populate the argument values.
        args->SetSize(2);
        args->SetString(0, strUser);
        args->SetString(1, strPassword);

        // Send the process message to the browser process.
        CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, msg);

我把那个cef_js_integration示例中收到的登陆消息(Render进程)发送给Browser进程。

    1. 处理消息

Browser进程这边,重写CefClient::OnProcessMessageReceived()这个方法来处理跨进程消息。

以cef_js_integration为例,是在ClientHandler中重写了OnProcessMessageReceived方法:

bool ClientHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
    CefProcessId source_process,
    CefRefPtr<CefProcessMessage> message)
{
    const std::string& messageName = message->GetName();
    if (messageName == "login_msg") 
    {   
        // extract message
        CefRefPtr<CefListValue> args = message->GetArgumentList();
        CefString strUser = args->GetString(0);
        CefString strPassword = args->GetString(1);
        TCHAR szLog[256] = { 0 };
        _stprintf_s(szLog, 256, _T("BrowserProcess, user - %s, password - %s
"), strUser.c_str(), strPassword.c_str());
        OutputDebugString(szLog);

        //send reply to render process
        CefRefPtr<CefProcessMessage> outMsg = CefProcessMessage::Create("login_reply");

        // Retrieve the argument list object.
        CefRefPtr<CefListValue> replyArgs = outMsg->GetArgumentList();

        // Populate the argument values.
        replyArgs->SetSize(1);
        replyArgs->SetInt(0, 0);

        // Send the process message to the renderer process.
        browser->SendProcessMessage(PID_RENDERER, outMsg);

        return true;
    }
    return false;
}

可以看到,上面的代码又给Render进程发了个消息。

Render进程这边, 重写CefRenderProcessHandler::OnProcessMessageReceived()方法来处理来自Browser进程的消息,具体代码在ClientAppRender类中:

bool ClientAppRenderer::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
    CefProcessId source_process,
    CefRefPtr<CefProcessMessage> message)
{
    const std::string& messageName = message->GetName();
    if (messageName == "login_reply")
    {
        // extract message
        CefRefPtr<CefListValue> args = message->GetArgumentList();
        int status = args->GetInt(0);
        OutputDebugString(status == 0 ? _T("Renderer process, login ok
") : _T("Renderer process, login failed
"));
        CefRefPtr<CefFrame> frame = browser->GetMainFrame();
        frame->Executejavascript("alert('Got Login Reply from Browser process')", frame->GetURL(), 0);
        return true;
    }
    return false;
}

好啦,这就是整个过程了。

其他参考文章:

以上是关于CEF中Browser进程与Render进程间通信的主要内容,如果未能解决你的问题,请参考以下文章

PPAPI与Browser间使用AsyncIPC通信

cef合并渲染进程

cef合并渲染进程

cefframerender是啥进程

调试CEF3程序的方法

Browser进程和浏览器内核(Renderer进程)的通信过程