如何在CEF JS与browser进程间异步通信
2个回答
展开全部
Browser JS Time项是browser.js更新时间戳。用于更新。Browser JavaScript项是对browser.js的设定。
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
展开全部
参考如下:
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);
...
}
注意我在main函数之外定义了一个CefMessageRouterConfig的实例,然后在main函数中设置了query和cancel这两个函数。它们定义了可以在html的js代码里使用的方法,比如根据上面代码,你可以用window.cefQuery({…})。
2)创建CefMessageRouterBrowserSide的实例
browser进程这边需要一个CefMessageRouterBrowserSide的实例来处理renderer进程发过来的消息。建议把这个实例作为成员变量放在CefClient的派生类中,因为它CefMessageRouterBrowserSide定义了一些方法,需要在指定的地方调用。
声明和初始化的代码片段:
CefRefPtr m_browser_side_router;
...
extern CefMessageRouterConfig g_messageRouterConfig;
m_browser_side_router = CefMessageRouterBrowserSide::Create(g_messageRouterConfig);
...
3)调用预定义方法
CefMessageRouterBrowserSide预定义了下列接口,需要在指定地方调用:
// call from CefClient::OnProcessMessageReceived
bool OnProcessMessageReceived(...)
// call from CefLifeSpanHandler::OnBeforeClose()
void OnBeforeClose(CefRefPtr browser)
// call from CefRequestHandler::OnRenderProcessTerminated()
void OnRenderProcessTerminated(CefRefPtr browser)
// call from CefRequestHandler::OnBeforeBrowse()
void OnBeforeBrowse(...)
所以,我们的这个ClientHandler类,声明如下:
class ClientHandler : public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefRequestHandler
{
...
}
ClientHandler要实现CefClient的OnProcessMessageReceived、CefLifeSpanHandler的OnBeforeClose、CefRequestHandler的OnRenderProcessTerminated和OnBeforeBrowse方法,在这些方法里调用CefMessageRouterBrowserSide的同名方法即可。代码片段如下:
void ClientHandler::OnBeforeClose(CefRefPtr browser)
{
CEF_REQUIRE_UI_THREAD();
m_browser_side_router->OnBeforeClose(browser);
...
}
bool ClientHandler::OnProcessMessageReceived(CefRefPtr browser,
CefProcessId source_process,
CefRefPtr message)
{
if (m_browser_side_router->OnProcessMessageReceived(browser, source_process, message)) return true;
return false;
}
bool ClientHandler::OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool is_redirect)
{
m_browser_side_router->OnBeforeBrowse(browser, frame);
return false;
}
void ClientHandler::OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status)
{
m_browser_side_router->OnRenderProcessTerminated(browser);
}
4) 在browser进程里实现处理JS查询的handler
CefMessageRouterBrowserSide定义了一个内部类Handler,继承它:
class BrowserSideJSHandler : public CefMessageRouterBrowserSide::Handler
{
public:
BrowserSideJSHandler();
virtual bool OnQuery(CefRefPtr browser,
CefRefPtr frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr callback);
virtual void OnQueryCanceled(CefRefPtr browser,
CefRefPtr frame,
int64 query_id);
};
实现 OnQuery 和 OnQueryCanceled两个方法:
bool BrowserSideJSHandler::OnQuery(CefRefPtr browser,
CefRefPtr frame, int64 query_id,
const CefString& request, bool persistent, CefRefPtr 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 browser, CefRefPtr frame, int64 query_id)
{
//cancel our async query task...
}
5)给CefMessageRouterBrowserSide的实例添加handler
我在ClientHandler类中定义了一个BrowserSideJSHandler的实例,类似下面:
class ClientHandler : public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefRequestHandler
{
...
CefRefPtr m_browser_side_router;
BrowserSideJSHandler m_jsHandler;
...
}
然后在ClientHandler构造函数中加入了下列代码:
m_browser_side_router->AddHandler(&m_jsHandler, true);
上面的代码把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 m_renderer_side_router;
...
};
创建类似下面:
m_renderer_side_router = CefMessageRouterRendererSide::Create(g_messageRouterConfig);
3) 调用预定义方法
CefMessageRouterRendererSide定义了下面三个预定义方法:
void OnContextCreated(...)
void OnContextReleased(...)
bool OnProcessMessageReceived(...)
这三个方法需要在CefRenderProcessHandler的派生类的同名方法里调用,我的代码片段:
void ClientAppRenderer::OnContextCreated(CefRefPtr browser,
CefRefPtr frame,
CefRefPtr context)
{
m_renderer_side_router->OnContextCreated(browser, frame, context);
}
void ClientAppRenderer::OnContextReleased(CefRefPtr browser,
CefRefPtr frame, CefRefPtr context)
{
m_renderer_side_router->OnContextReleased(browser, frame, context);
}
bool ClientAppRenderer::OnProcessMessageReceived(CefRefPtr browser,
CefProcessId source_process,
CefRefPtr message)
{
if (m_renderer_side_router->OnProcessMessageReceived(browser, source_process, message)) return true;
return false;
}
好啦,renderer进程这边的事儿干完了。接下来就可以在html里写js代码调用cefQuery方法了。
html中的js
html这一侧很简单,我的测试代码如下:
<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>
Query String:
关键的代码起始就一个函数:
function doQuery() {
window.cefQuery({
request: document.getElementById("query").value,
persistent: false,
onSuccess: function(response) { alert(response); },
onFailure: function(code, msg) { alert(code + " - " + msg); }
}
);
}
cefQuery方法接受一个JS对象,如你所见,request、persistent可以对应到BrowserSideJSHandler::OnQuery的参数上,onSuccess和onFailure则在renderer进程里做了转换,到browser进程里对应到了CefMessageRouterBrowserSide::Callback的Success和Failure方法上。
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);
...
}
注意我在main函数之外定义了一个CefMessageRouterConfig的实例,然后在main函数中设置了query和cancel这两个函数。它们定义了可以在html的js代码里使用的方法,比如根据上面代码,你可以用window.cefQuery({…})。
2)创建CefMessageRouterBrowserSide的实例
browser进程这边需要一个CefMessageRouterBrowserSide的实例来处理renderer进程发过来的消息。建议把这个实例作为成员变量放在CefClient的派生类中,因为它CefMessageRouterBrowserSide定义了一些方法,需要在指定的地方调用。
声明和初始化的代码片段:
CefRefPtr m_browser_side_router;
...
extern CefMessageRouterConfig g_messageRouterConfig;
m_browser_side_router = CefMessageRouterBrowserSide::Create(g_messageRouterConfig);
...
3)调用预定义方法
CefMessageRouterBrowserSide预定义了下列接口,需要在指定地方调用:
// call from CefClient::OnProcessMessageReceived
bool OnProcessMessageReceived(...)
// call from CefLifeSpanHandler::OnBeforeClose()
void OnBeforeClose(CefRefPtr browser)
// call from CefRequestHandler::OnRenderProcessTerminated()
void OnRenderProcessTerminated(CefRefPtr browser)
// call from CefRequestHandler::OnBeforeBrowse()
void OnBeforeBrowse(...)
所以,我们的这个ClientHandler类,声明如下:
class ClientHandler : public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefRequestHandler
{
...
}
ClientHandler要实现CefClient的OnProcessMessageReceived、CefLifeSpanHandler的OnBeforeClose、CefRequestHandler的OnRenderProcessTerminated和OnBeforeBrowse方法,在这些方法里调用CefMessageRouterBrowserSide的同名方法即可。代码片段如下:
void ClientHandler::OnBeforeClose(CefRefPtr browser)
{
CEF_REQUIRE_UI_THREAD();
m_browser_side_router->OnBeforeClose(browser);
...
}
bool ClientHandler::OnProcessMessageReceived(CefRefPtr browser,
CefProcessId source_process,
CefRefPtr message)
{
if (m_browser_side_router->OnProcessMessageReceived(browser, source_process, message)) return true;
return false;
}
bool ClientHandler::OnBeforeBrowse(CefRefPtr browser, CefRefPtr frame, CefRefPtr request, bool is_redirect)
{
m_browser_side_router->OnBeforeBrowse(browser, frame);
return false;
}
void ClientHandler::OnRenderProcessTerminated(CefRefPtr browser, TerminationStatus status)
{
m_browser_side_router->OnRenderProcessTerminated(browser);
}
4) 在browser进程里实现处理JS查询的handler
CefMessageRouterBrowserSide定义了一个内部类Handler,继承它:
class BrowserSideJSHandler : public CefMessageRouterBrowserSide::Handler
{
public:
BrowserSideJSHandler();
virtual bool OnQuery(CefRefPtr browser,
CefRefPtr frame,
int64 query_id,
const CefString& request,
bool persistent,
CefRefPtr callback);
virtual void OnQueryCanceled(CefRefPtr browser,
CefRefPtr frame,
int64 query_id);
};
实现 OnQuery 和 OnQueryCanceled两个方法:
bool BrowserSideJSHandler::OnQuery(CefRefPtr browser,
CefRefPtr frame, int64 query_id,
const CefString& request, bool persistent, CefRefPtr 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 browser, CefRefPtr frame, int64 query_id)
{
//cancel our async query task...
}
5)给CefMessageRouterBrowserSide的实例添加handler
我在ClientHandler类中定义了一个BrowserSideJSHandler的实例,类似下面:
class ClientHandler : public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefRequestHandler
{
...
CefRefPtr m_browser_side_router;
BrowserSideJSHandler m_jsHandler;
...
}
然后在ClientHandler构造函数中加入了下列代码:
m_browser_side_router->AddHandler(&m_jsHandler, true);
上面的代码把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 m_renderer_side_router;
...
};
创建类似下面:
m_renderer_side_router = CefMessageRouterRendererSide::Create(g_messageRouterConfig);
3) 调用预定义方法
CefMessageRouterRendererSide定义了下面三个预定义方法:
void OnContextCreated(...)
void OnContextReleased(...)
bool OnProcessMessageReceived(...)
这三个方法需要在CefRenderProcessHandler的派生类的同名方法里调用,我的代码片段:
void ClientAppRenderer::OnContextCreated(CefRefPtr browser,
CefRefPtr frame,
CefRefPtr context)
{
m_renderer_side_router->OnContextCreated(browser, frame, context);
}
void ClientAppRenderer::OnContextReleased(CefRefPtr browser,
CefRefPtr frame, CefRefPtr context)
{
m_renderer_side_router->OnContextReleased(browser, frame, context);
}
bool ClientAppRenderer::OnProcessMessageReceived(CefRefPtr browser,
CefProcessId source_process,
CefRefPtr message)
{
if (m_renderer_side_router->OnProcessMessageReceived(browser, source_process, message)) return true;
return false;
}
好啦,renderer进程这边的事儿干完了。接下来就可以在html里写js代码调用cefQuery方法了。
html中的js
html这一侧很简单,我的测试代码如下:
<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>
Query String:
关键的代码起始就一个函数:
function doQuery() {
window.cefQuery({
request: document.getElementById("query").value,
persistent: false,
onSuccess: function(response) { alert(response); },
onFailure: function(code, msg) { alert(code + " - " + msg); }
}
);
}
cefQuery方法接受一个JS对象,如你所见,request、persistent可以对应到BrowserSideJSHandler::OnQuery的参数上,onSuccess和onFailure则在renderer进程里做了转换,到browser进程里对应到了CefMessageRouterBrowserSide::Callback的Success和Failure方法上。
本回答被提问者采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询