如何在浏览器进程中调用CefV8Context :: Eval()方法?

Ker*_*ery 1 c++ chromium chromium-embedded

我想调用CefV8Context :: Eval函数并在浏览器进程的UI线程中获取返回值.但CEF3 C++ API Docs声明V8句柄只能从创建它们的线程访问.用于创建V8句柄的有效线程包括呈现进程主线程(TID_RENDERER)和WebWorker线程.这是否意味着我应该使用进程间通信(CefProcessMessage)来调用该方法并获取返回值?如果是这样,如何在同步模式下执行此操作?

Sha*_*adh 9

简答:CefFrame::ExecuteJavaScript对于简单的请求会起作用.对于更复杂的,您必须放弃一个级别的同步或使用自定义消息循环.


我理解你想要做的是执行一些Javascript代码作为本机App的UI线程的一部分.有两种可能性:

  1. 它是通用的JS代码,并不真正访问JS中的任何变量或函数,因此没有上下文.这意味着Cef可以启动新的V8上下文并执行您的代码 - 请参阅CefFrame::ExecuteJavaScript().引用CEF的JS Integration链接上的示例:

    CefRefPtr浏览器= ...; CefRefPtr frame = browser-> GetMainFrame(); frame-> ExecuteJavaScript("alert('ExecuteJavaScript works!');",frame-> GetURL(),0);

  2. 它是带有上下文的JS代码.在这种情况下,请继续阅读.

是的 - CEF的设计使得只有RenderProcess才能访问V8引擎,您必须使用a CefProcessMessage来转到浏览器并在那里进行评估.你听起来像你已经知道如何做到这一点.我将把我的答案链接给其他没有的人,可能会在以后偶然发现:Chromium Embedded Framework的本机功能的后台流程

从浏览器到渲染进程的CEFProcessMessage是必须同步请求的地方.

因此,在将逻辑发送到渲染过程之后,您将需要执行javascript代码的实际执行.谢天谢地,这很简单 - 同样的JS集成链接继续说:

本机代码可以使用ExecuteFunction()和ExecuteFunctionWithContext()方法执行JS函数

最好的部分 - 执行似乎是同步的(我说似乎,因为我找不到具体的文档).示例中的用法说明了这一点:

if (callback_func_->ExecuteFunctionWithContext(callback_context_, NULL, args, retval, exception, false)) {
  if (exception.get()) {
    // Execution threw an exception.
  } else {
    // Execution succeeded.
  }
}
Run Code Online (Sandbox Code Playgroud)

您会注意到第二行假设第一行已完成执行,并且所述执行结果可用.因此,CefV8Value :: ExecuteFunction()调用本质上是同步的.

所以问题可以归结为 - 如何同步将CefProcessMessage从浏览器发布到渲染器进程?.不幸的是,班级本身并没有这样做.更重要的是,IPC Wiki页面明确禁止它:

从渲染器的角度来看,某些消息应该是同步的.这种情况主要发生在我们应该返回某个WebKit调用时,但我们必须在浏览器中执行此操作.此类消息的示例包括拼写检查和获取JavaScript的cookie.禁止同步浏览器到渲染器IPC以防止在可能存在碎片的渲染器上阻塞用户界面.

这是一件大事吗?嗯,我真的不知道,因为我没有遇到这种需要 - 对我而言,没关系,因为浏览器的消息循环将继续旋转等待某事做,并且在渲染器发送进程消息之前不会收到任何信息. JS的结果.浏览器获取其他内容的唯一方法是在发生某些交互时,由于渲染器阻塞,因此无法进行交互.

如果你真的肯定需要时间同步性,我建议您使用自定义的消息循环这就要求CefDoMessageLoopWork()在每个迭代上.这样,您可以设置一个标志来暂停循环工作,直到从渲染器收到消息.需要注意的是CefDoMessageLoopWork()CefRunMessageLoop()互斥的,不能相互合作-你要么自己管理的循环,还是让CEF为您代劳.

这很长,涵盖了你可能想做的大部分内容 - 希望它有所帮助!