CEF 中从客户端到浏览器的消息传递序列化

Serialization for Messaging in CEF from Client to Browser

我有一个 Chromium 嵌入式框架 (CEF) 应用程序,我们希望在客户端 JavaScript 端与浏览器端之间进行通信。 到目前为止,我们有可能使用通用消息路由器 GenericMessageRouter: 客户端然后执行类似这样的操作来向浏览器线程发送消息:

var request_id = window.cefQuery({
request: 'my_request',
persistent: false,
onSuccess: function(response) {},
onFailure: function(error_code, error_message) {}
});

// which will be receiven by the browser with

bool OnQuery(CefRefPtr<CefBrowser> browser,
                CefRefPtr<CefFrame> frame,
                int64 query_id,
                const CefString& request,
                bool persistent,
                CefRefPtr<Callback> callback)

我想知道如果我们要发送双向二进制数据(例如使用 Google 协议缓冲区的序列化数据),哪种解决方案最好。据我所知,ArrayBuffer 在 CEF 中并没有得到真正的支持,这有点不幸。我们是否也可以滥用 CefString 或者这是一个坏主意?

这是完美手册https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration

扩展类似于 window 绑定,只是它们会加载到每一帧的上下文中,并且一旦加载就无法修改。加载扩展时 DOM 不存在,在扩展加载期间尝试访问 DOM 将导致崩溃。扩展使用 CefRegisterExtension() 函数注册,该函数应从 CefRenderProcessHandler::OnWebKitInitialized() 方法中调用。

JS 函数

CEF 支持使用本机实现创建 JS 函数。函数是使用接受名称和 CefV8Handler 参数的 CefV8Value::CreateFunction() 静态方法创建的。只能在上下文中创建和使用函数(有关详细信息,请参阅 "Working with Contexts" 部分)。

CefRefPtr<CefV8Handler> handler = …;
CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);

客户端应用程序必须提供的 CefV8Handler 接口的实现。

class MyV8Handler : public CefV8Handler {
public:
  MyV8Handler() {}

  virtual bool Execute(const CefString& name,
                       CefRefPtr<CefV8Value> object,
                       const CefV8ValueList& arguments,
                       CefRefPtr<CefV8Value>& retval,
                       CefString& exception) OVERRIDE {
    if (name == "myfunc") {
      // Extract argument values
      // ...
      // Do work
      // ...
      // Return my string value.
      retval = CefV8Value::CreateString("My Value!");
      return true;
    }

    // Function does not exist.
    return false;
  }

  // Provide the reference counting implementation for this class.
  IMPLEMENT_REFCOUNTING(MyV8Handler);
};

函数和Window绑定

函数可用于创建复杂的 window 绑定。

void MyRenderProcessHandler::OnContextCreated(
    CefRefPtr<CefBrowser> browser,
    CefRefPtr<CefFrame> frame,
    CefRefPtr<CefV8Context> context) {
  // Retrieve the context's window object.
  CefRefPtr<CefV8Value> object = context->GetGlobal();

  // Create an instance of my CefV8Handler object.
  CefRefPtr<CefV8Handler> handler = new MyV8Handler();

  // Create the "myfunc" function.
  CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myfunc", handler);

  // Add the "myfunc" function to the "window" object.
  object->SetValue("myfunc", func, V8_PROPERTY_ATTRIBUTE_NONE);
}

来电JavaScript

<script language="JavaScript">
    alert(window.myfunc(myJSON)); // Calls the function "myFunc" and passes the JSON through function argument
</script>

函数和扩展

函数可用于创建复杂的扩展。请注意使用扩展时需要的 "native function" 前向声明。

void MyRenderProcessHandler::OnWebKitInitialized() {
  // Define the extension contents.
  std::string extensionCode =
    "var test;"
    "if (!test)"
    "  test = {};"
    "(function() {"
    "  test.myfunc = function(json) {"
    "    native function myfunc();"
    "    return myfunc(json);"
    "  };"
    "})();";

  // Create an instance of my CefV8Handler object.
  CefRefPtr<CefV8Handler> handler = new MyV8Handler();

  // Register the extension.
  CefRegisterExtension("v8/test", extensionCode, handler);
}

来电JavaScript

<script language="JavaScript">
    alert(test.myfunc(myJSON)); // Calls the function "myFunc" and passes the JSON through function argument
</script>

Google protobuf 不适合 JS 和原生函数之间的互操作。使用 JSON。 JS 对象可以透明地序列化为 JSON,反之亦然。