CEF内核,Browser进程与Renderer进程之间的通信

顺着我之前写的文章,关于MFC嵌入并使用CEF之后,实现了多选项卡、C++与JS通信等功能之后,CEF在C++里面的使用基本是差不多了,剩下的就是了解browser接口、Frame接口、Context接口以及BrowserProcessHandler和RenderProcessHandler接口,只要我们将所有接口方法理清楚弄明白,相信CEF在C++中的使用就可以告一段落了,顺着这个思路我观察到cefClient接口中有一个接口OnProcessMessageReceived和RenderProcessHandler中也有一个OnProcessMessageReceived接口,看注释就知道,这是处理不同进程发送过来的消息,我们知道CEF是由多进程方式实现的(默认情况,按照我前一篇文章可以改成单进程方式),不同进程之间通信就是通过浏览器CefBrowser的消息发送接口SendProcessMessage实现的,所以我们这章讲的就是有关如何在Browser进程与Renderer进程之间进行通信(当然所有的接口中还有有关上下文菜单、复制、拷贝等接口,但是我觉得进程通信这块更重要)。

       还是按照以往方式,首先摆出问题:

(1)Renderer进程如何发送消息给Browser进程

(2)Browser进程如何发送消息给Renderer进程

       围绕以上问题,在我原有的代码(http://download.csdn.net/detail/lixiang987654321/9602430)上回答以上两个问题,以下我们做一个简单的功能Render给Browser发一个消息,然后Browser验证后回复一个消息(cef中PID_BROWSER代表Browser浏览器进程,PID_RENDER代表Render进程):

(1)Renderer发送消息给Browser

通过我前一篇文章知道js引擎是运行在Renderer进程中的,在cefv8handler中js的处理函数中我们将函数名发送给browser进程,让其验证改函数,然后回复验证结果给Renderer进程,那么在Renderer中我们发送一个消息给Browser:

[cpp] view plain copy

 CEF内核,Browser进程与Renderer进程之间的通信CEF内核,Browser进程与Renderer进程之间的通信

  1. bool CV8JsHandler::Execute(const CefString& func_name,  
  2.                              CefRefPtr<CefV8Value> object,  
  3.                              const CefV8ValueList& arguments,  
  4.                              CefRefPtr<CefV8Value>& retval,  
  5.                              CefString& exception)  
  6. {  
  7.     // send message to browser process that method began to execute  
  8. <span style="color:#ff0000;"> CefRefPtr<CefProcessMessage> objMsg = CefProcessMessage::Create(_T("msg_from_render"));  
  9.     CefRefPtr<CefListValue> arglist = objMsg->GetArgumentList();  
  10.     arglist->SetString(0, /*CefV8Value::CreateString()*/func_name);  
  11.     CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, objMsg);</span>  
  12.   
  13.     if (func_name == _T("addFunction"))  
  14.     {  
  15.         int32 nSum = 0;  
  16.         for (size_t i = 0; i < arguments.size(); ++i)  
  17.         {  
  18.             if(!arguments[i]->IsInt())  
  19.                 return false;  
  20.             nSum += arguments[i]->GetIntValue();  
  21.         }  
  22.         retval = CefV8Value::CreateInt(nSum);  
  23.         return true;  
  24.     }  
  25.     else if (func_name == _T("hehe"))  
  26.     {  
  27.         retval = CefV8Value::CreateString(_T("hehe hehe!"));  
  28.         return true;  
  29.     }  
  30.       
  31.     else  
  32.     {  
  33.         return false;  
  34.     }  
  35. }

(2)Browser回复对应消息

 每一个Browser都有一个CefClient,cefclient实现所有消息或事件处理接口处理浏览器的所有事件,所以cefclient是运行在browser中的事件处理器,我们在Cefclient的实现中实现OnProcessMessageReceived接口,处理来自其他进程的消息:

[cpp] view plain copy

 CEF内核,Browser进程与Renderer进程之间的通信CEF内核,Browser进程与Renderer进程之间的通信

  1. bool CCefBrowserEventHandler::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,  
  2.                                                        CefProcessId source_process,  
  3.                                                        CefRefPtr<CefProcessMessage> message) OVERRIDE  
  4. {  
  5.     if (message->GetName() == _T("msg_from_render"))  
  6.     {  
  7.         CefRefPtr<CefListValue> argList = message->GetArgumentList();  
  8.         CefString strFunctionName = argList->GetString(0);  
  9.   
  10.         bool bAllow = false;  
  11.         if (strFunctionName == _T("addFunction"))  
  12.         {  
  13.             bAllow = true;  
  14.         }  
  15.   
  16.         CefRefPtr<CefProcessMessage> msg_back = CefProcessMessage::Create(_T("func_back"));  
  17.         msg_back->GetArgumentList()->SetString(0, strFunctionName);  
  18.         msg_back->GetArgumentList()->SetBool(1, bAllow);  
  19.         browser->SendProcessMessage(PID_RENDERER, msg_back);  
  20.         return true;  
  21.     }  
  22.     return false;   // has handle for the message  
  23. }

   我做的简单操作就是,当直接addFunction函数的时候验证有效,否则无效!返回将结果回复给PID_RENDER进程。

(3)Renderer处理回复

    在Render进程处理器中处理OnProcessMessageReceived接口,检查回复:

[cpp] view plain copy

 CEF内核,Browser进程与Renderer进程之间的通信CEF内核,Browser进程与Renderer进程之间的通信

  1. bool CCefBrowserApp::OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,  
  2.                                                CefProcessId source_process,  
  3.                                                CefRefPtr<CefProcessMessage> message)   
  4. {  
  5.     if (message->GetName() == _T("func_back"))  
  6.     {  
  7.         // extract message  
  8.         CefRefPtr<CefListValue> args = message->GetArgumentList();  
  9.         CefString strFunctionName = args->GetString(0);  
  10.         bool bAllow = args->GetBool(1);  
  11.   
  12.         CString strMsg;  
  13.         strMsg.Format(_T("alert('function %s status %d')"), strFunctionName.c_str(), bAllow);  
  14.         browser->GetMainFrame()->ExecuteJavaScript((LPCTSTR)strMsg, browser->GetMainFrame()->GetURL(), 0);  
  15.         return true;  
  16.     }  
  17.     return false;  

      通过以上一个消息循环,大家知道cef中Render进程和browser进程通信其实很简单,就是通过浏览器Browser的SendProcessMessage方法实现的,这里的这个方法就类似于MFC的Postmessage方法,它是异步的,不是同步的方法。

      关于CEF中进程通信很简单,我就说道这里,截图如下:

      browser中收到render消息:

      CEF内核,Browser进程与Renderer进程之间的通信

      browser回复消息到render中,render收到结果:

     CEF内核,Browser进程与Renderer进程之间的通信

      browser中收到render消息:

     CEF内核,Browser进程与Renderer进程之间的通信

      browser回复消息到render中,render收到结果:

     CEF内核,Browser进程与Renderer进程之间的通信

     CEF内核,Browser进程与Renderer进程之间的通信

     

     实例代码:http://download.csdn.net/detail/lixiang987654321/9602615

上一篇:Three.js 学习笔记之一 Helloworld(翻译)


下一篇:‎Cocos2d-x 学习笔记(25) 渲染 绘制 Render