[CEF] 官方资料汇总 (含JaveScript与C++通信、IPC)

CEF的branch 都是发布的正式分支(开发自己的app时使用branch的代码) Master是平时的开发分支

官方已编译好的dll,因为涉及到版权问题,不能播放很多音视频,需要自己手动修改配置并重新编译chromium。

 

官方资料:https://bitbucket.org/chromiumembedded/cef/wiki/Home

建议先看完资料再看官方demo,不然代码逻辑理解起来很困难。其中重要的几个文档是:

BranchesAndBuilding 获取和编译已发布的cef版本

GeneralUsage 使用手册(内容很丰富 包括cef的多进程架构和常用的基础概念)

JavaScriptIntegration JS和C++的交互

 

基于CEF的程序在运行时,会启动多个进程(browser process,render process,other process)

其中后面两种进程都是由CEF底层启动,这种exe称为宿主程序,根据你browser process中的配置,宿主程序既可以和你的browser process共用一个exe,也可以另外写一个exe(具体可以参考官方提供demo或前面提到的文档)

 

如上,因为render process和other process是不同的进程,所以在你调试官方提供的cefclient工程时,发现很多代码你的断点都无法命中,那并不代表这段代码没有被执行,很可能是因为这段代码并不是执行在browser process中。为了调试这种代码,可以安装vs插件,修改vs配置,使其可以调试主进程启动的子进程。具体参考我另一个转载的博文:

https://blog.csdn.net/felicityWSH/article/details/80651847

 

======================== 各种通信机制 ==========================

JaveScript和Render-C++通信 (Window binding & Extensions):

https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md

https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-inter-process-communication-ipc

通过Windows binding和Extensions的方法,JS调用C++函数的流程一般如下:

1. 注册function,传递render中的CefV8Handler对象

2. JS调用render中的CefV8Handler::Execute

3. 如果不需要browser执行,render直接处理后调用Execute参数中的function,给js返回执行结果,结束通信。

4. 如果需要browser执行,render保存Execute参数中的function、context等参数,然后通过SendProcessMessage发送给browser,为了收到回复的消息后能找到保存的对应的function等信息,需要在发给browser的参数中赋一些id之类的信息

5. browser通过CefClient::OnProcessMessageReceived收到render的消息,处理完后通过SendProcessMessage发送结果给render(收到的id信息需要原样返回)

6. render通过OnProcessMessageReceived收到browser传回来的结果,根据之前发送的id信息,可以找到保存的对应的function和context,执行ExecuteFunction()或ExecuteFunctionWithContext()将结果返回给js,然后删除保存的function等信息。

注意:因为此时已经不在v8 context的上下文范围中,所以需要调用以下函数:

CefV8Context::Enter()
CefV8Context::Exit()

根据官方文档:The Enter() and Exit() methods should only be used:

  1. When creating a V8 object, function or array outside of an existing context. For example, when creating a JS object in response to a native menu callback.
  2. When creating a V8 object, function or array in a context other than the current context. For example, if a call originating from frame1 needs to modify the context of frame2.

 

Render和 Browser的IPC通信 

https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-inter-process-communication-ipc

消息发送函数:CefBrowser::SendProcessMessage

从Browser进程发送到Render进程的消息,将会在以下函数接收:

CefRenderProcessHandler::OnProcessMessageReceived()

从Render进程发送到Browser进程的消息,将会在以下函数接收:

CefClient::OnProcessMessageReceived()

cefClient的代码示例:

Render发送消息:

// class ClientAppRenderer : public ClientApp, public CefRenderProcessHandler
// virtual void OnFocusedNodeChanged
             
           void OnFocusedNodeChanged(CefRefPtr<ClientAppRenderer> app,
                    CefRefPtr<CefBrowser> browser,
                    CefRefPtr<CefFrame> frame,
                    CefRefPtr<CefDOMNode> node) OVERRIDE
                {
                    bool is_editable = (node.get() && node->IsEditable());
                    if (is_editable != last_node_is_editable_)
                    {
                        // Notify the browser of the change in focused element type.
                        last_node_is_editable_ = is_editable;

                        CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create(kFocusedNodeChangedMessage);
                        message->GetArgumentList()->SetBool(0, is_editable);
                        browser->SendProcessMessage(PID_BROWSER, message);
                    }
                }

Browser响应消息:

// class ClientHandler : public CefClient,

    bool ClientHandler::OnProcessMessageReceived( 
        CefRefPtr<CefBrowser> browser,
        CefProcessId source_process,
        CefRefPtr<CefProcessMessage> message)
    {
        CEF_REQUIRE_UI_THREAD();

        if (message_router_->OnProcessMessageReceived(browser, source_process, message))
            return true;

        // Check for messages from the client renderer.
        std::string message_name = message->GetName();
        if (message_name == kFocusedNodeChangedMessage) 
        {
            // A message is sent from ClientRenderDelegate to tell us whether the
            // currently focused DOM node is editable. Use of |focus_on_editable_field_|
            // is redundant with CefKeyEvent.focus_on_editable_field in OnPreKeyEvent
            // but is useful for demonstration purposes.
            focus_on_editable_field_ = message->GetArgumentList()->GetBool(0);
            return true;
        }

        return false;
    }

 

JaveScript和 Browser-C++通信(消息路由)

https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-asynchronous-javascript-bindings

详见cef_message_router.h 中的注释

JS的请求方法:

function sendMessage()
{
    window.cefQuery({ // 此处的cefQuery 函数名就是你程序中 创建消息路由时 CefMessageRouterConfig中指定的函数名称
    request: 'BindingTest:' + document.getElementById("message").value,
    onSuccess: function (response)
    {
        document.getElementById('result').value = 'Response: ' + response;
    },
    onFailure: function (error_code, error_message)
    {
        // do something
    }
    });
}

对应到browser的回调函数:

class CefMessageRouterBrowserSide::Handler

virtual bool OnQuery(CefRefPtr<CefBrowser> browser,

                CefRefPtr<CefFrame> frame,

                int64 query_id,

                const CefString& request, // 请求的参数

                bool persistent,

                CefRefPtr<Callback> callback) // 成功或失败以及返回参数,都是通过调用callback的函数进行回传

JS的请求参数只有一个CefString,如果有多个参数,需要browser自己从中解析

如果JS的请求处理成功,browser只能回传一个CefString的参数(Callback::Success)

如果JS的请求处理失败,browser只能回传一个CefString、一个int的参数(Callback::Failure)

JS的Query会经过消息路由,到达browser,browser中会遍历之前所有注册过的handle,每个handle在Handler::OnQuery中选择忽略或处理该请求,如果选择处理,成功的话必须调用Callback::Success,失败的话必须调用Callback::Failure。如果browser中所有handle都没有处理这个请求,则js中会调用onFailure,errorcode会被自动填充为-1

消息路由的创建
CefMessageRouterConfig中有两个参数,指定js的函数调用名称,默认是cefQuery和cefQueryCancel。
注意:render和browser进程创建消息路由的参数必须一致、JS的函数调用名称也要一致。

browser:

CefMessageRouterConfig config;
message_router_ = CefMessageRouterBrowserSide::Create(config);
message_router_->AddHandler(MyHandler*, false); 
// class MyHandler : public CefMessageRouterBrowserSide::Handler
// JS的请求 会调用到MyHandle实现的虚函数OnQuery中

render:

CefMessageRouterConfig config;
message_router_ = CefMessageRouterRendererSide::Create(config);

这两个对象创建后,之后的逻辑调用可参考cefClient的代码。

cefClient中测试该功能的UI操作是:cefclient>top menu>tests>Other Tests>

 

Render中注册js的函数

https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage#markdown-header-inter-process-communication-ipc

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值