CEF中JavaScript与C++交互

Browser与Render进程

从cefsimple開始吧,cefsimple_win.cc中的wWinMain函数中调用了CefExecuteProcess()方法来检測是否要启动其他的子进程。此处的CefExecuteProcess是在libcef_dll_wrapper.cc中的,它内部又调用了cef_execute_process方法(libcef_dll.cc),cef_execute_process又调用了libcef/browser/context.cc文件内实现的CefExecuteProcess方法。这种方法代码例如以下:

 
  1. int CefExecuteProcess(const CefMainArgs& args,
  2. CefRefPtr application,
  3. void* windows_sandbox_info) {
  4. base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
  5. #if defined(OS_WIN)
  6. command_line.ParseFromString(::GetCommandLineW());
  7. #else
  8. command_line.InitFromArgv(args.argc, args.argv);
  9. #endif
  10.  
  11. // Wait for the debugger as early in process initialization as possible.
  12. if (command_line.HasSwitch(switches::kWaitForDebugger))
  13. base::debug::WaitForDebugger(60, true);
  14.  
  15. // If no process type is specified then it represents the browser process and
  16. // we do nothing.
  17. std::string process_type =
  18. command_line.GetSwitchValueASCII(switches::kProcessType);
  19. if (process_type.empty())
  20. return -1;
  21.  
  22. CefMainDelegate main_delegate(application);
  23.  
  24. // Execute the secondary process.
  25. #if defined(OS_WIN)
  26. sandbox::SandboxInterfaceInfo sandbox_info = {0};
  27. if (windows_sandbox_info == NULL) {
  28. content::InitializeSandboxInfo(&sandbox_info);
  29. windows_sandbox_info = &sandbox_info;
  30. }
  31.  
  32. content::ContentMainParams params(&main_delegate);
  33. params.instance = args.instance;
  34. params.sandbox_info =
  35. static_cast(windows_sandbox_info);
  36.  
  37. return content::ContentMain(params);
  38. #else
  39. content::ContentMainParams params(&main_delegate);
  40. params.argc = args.argc;
  41. params.argv = const_cast(args.argv);
  42.  
  43. return content::ContentMain(params);
  44. #endif

它分析了命令行參数,提取”type”參数。假设为空。说明是Browser进程,返回-1。这样一路回溯到wWinMain方法里,然后開始创建Browser进程相关的内容。

假设”type”參数不为空,做一些推断,最后调用了content::ContentMain方法,直到这种方法结束。子进程随之结束。

content::ContentMain方法再追溯下去,就到了chromium的代码里了。在chromium/src/content/app/content_main.cc文件里。

详细我们不分析了,感兴趣的能够去看看。

分析了CefExecuteProcess方法我们知道,Browser进程在cefsimple_win.cc内调用了CefExecuteProcess之后做了进一步的配置,这个是在simple_app.cc内完毕的,详细就是SimpleApp::OnContextInitialized()这种方法。代码例如以下:

 
  1. void SimpleApp::OnContextInitialized() {
  2. CEF_REQUIRE_UI_THREAD();
  3.  
  4. CefWindowInfo window_info;
  5.  
  6. window_info.SetAsPopup(NULL, "cefsimple");
  7.  
  8. // SimpleHandler implements browser-level callbacks.
  9. CefRefPtr handler(new SimpleHandler());
  10.  
  11. // Specify CEF browser settings here.
  12. CefBrowserSettings browser_settings;
  13.  
  14. std::string url;
  15.  
  16. CefRefPtr command_line =
  17. CefCommandLine::GetGlobalCommandLine();
  18. url = command_line->GetSwitchValue("url");
  19. if (url.empty())
  20. url = "http://www.google.com";
  21.  
  22. CefBrowserHost::CreateBrowser(window_info, handler.get(), url,
  23. browser_settings, NULL);
  24. }

能够看到。这里创建SimpleHandler,并传递给CefBrowserHost::CreateBrowser去使用。

如今我们清楚了,Browser进程,须要CefApp(SimpleApp实现了这个接口)和CefClient(SimpleHandler实现了这个接口)。而Renderer进程仅仅要CefApp。

另外,CEF还定义了CefBrowserProcessHandler和CefRenderProcessHandler两个接口,分别来处理Browser进程和Render进程的个性化的通知。

因此,Browser进程的App一般还须要实现CefBrowserProcessHandler接口,Renderer进程的App一般还须要实现CefRenderProcessHandler接口。这里https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage有详细说明。

像cefsimple这个演示样例中的SimpeApp,没有实现CefRenderProcessHandler接口,没有针对Renderer进程做特别处理,所以当它作为Render进程时。会缺失一部分功能。

比方JS与Native代码交互,这正是我们想要的。

假设要实现JS与Native代码交互,最好分开实现Browser进程须要的CefApp和Render进程须要的CefApp。

像以下这样:

 
  1. class ClientAppRenderer : public CefApp,
  2. public CefRenderProcessHandler
  3. {
  4. ...
  5. }
  6.  
  7. class ClientAppBrowser : public CefApp,
  8. public CefBrowserProcessHandler
  9. {
  10. ...
  11. }

当我们实现了CefRenderProcessHandler接口,就能够在其OnContextCreated()方法中获取到CefFrame相应的window对象。在它上面绑定一些JS函数或对象。然后JS代码里就能够通过window对象訪问。假设是函数。就会调用到我们实现的CefV8Handler接口的Execute方法。

第二种实现JS与Native交互的方式,是在实现CefRenderProcessHandler的OnWebKitInitialized()方法时导出JS扩展,详细參考https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md,有详细说明。

cef_js_integration项目

cef_js_integration是非常easy的演示样例。用来演示JS与Native的交互。它在一个项目内实现了ClientAppBrowser、ClientAppRenderer、ClientAppOther三种CefApp。分别相应Browser、Render及其他类别的三种进程。

JS和Native代码的交互发生在Render进程。App须要继承CefRenderProcessHandler来整合JS相关功能。因此在应用在启动时做了进程类型推断。依据不同的进程类型创建不同的CefApp。

这个演示样例演示了三种JS交互方式(參见https://bitbucket.org/chromiumembedded/cef/wiki/JavaScriptIntegration.md): 

- 在native代码中通过CefFrame::ExecuteJavaScript()来运行JavaScript代码 

- 将函数或对象绑定到CefFrame相应的window对象上。JS代码通过window对象訪问native代码导出的函数或对象 

- 使用CefRegisterExtension()注冊JS扩展,JS直接訪问注冊到JS Context中的对象

这个项目參考了cefsimple、cefclient,还有https://github.com/acristoffers/CEF3SimpleSample,终于它比cefsimple复杂一点,比cefclient简单非常多。

你可能感兴趣的:(MFC)