首页 > 代码库 > CEF3研究(二)

CEF3研究(二)

  1. 应用程序结构

每个CEF3应用程序都有一个相同的结构:

  • 提供一个入口函数以初始化CEF和运行每个子进程逻辑和CEF消息处理
  • 提供一个CefApp子类处理某个进程的回调
  • 提供一个CefClinet子类处理某个浏览进程的回调
  • 调用CefBrowserHost::CreateBrowser()函数创建浏览进程实例并使用CefLifeSpanHandler来管理浏览生命周期

     2. 入口函数

CEF3应用程序都是以多进程方式运行的。这些进程都可以使用相同的可执行文件和独立的可执行文件被分配在每个子进程上。每个可执行进程都有一个入口函数。
每个CEF3子进程运行时使用运行行来指定配置信息并通过CefMainArgs结构传递给CefExecuteProcess函数,CefMainArgs结构是跨平台的。
如:
 CefMainArgs main_args(argc, argv); 
 CefMainArgs main_args(hInstance);

3.单可执行体-单进程运行方式

 当单可执行体时行时,入口函数CefExecuteProcess在不同进程类型之间需要区分。单可执行体结构只支持window和linux,不支持macos

4. 分离的子进程可执行体-多进程运行方式

当使用一个分离的子进程执行体时需要两个分离的进程和入口函数。

5. 消息循环集成

 CEF可集成已经存在的应用程序消息循环来代替它自己的消息循环。有2种方式:

    1. 正常的调用CefDoMessageLoopWork() 函数来代替调用 CefRunMessageLoop()。每调用 CefDoMessageLoopWork()函数会对CEF消息循环执行单一集成。
      应该谨慎使用这种方法。调用的方法也经常会挨饿CEF消息循环凑并且浏览器性能产生影响。调用方法过于频繁地将影响CPU使用率。
    2.  设置 CefSettings.multi_threaded_message_loop = true(仅Windows平台),这会引起CEF从主应用程序线程以单个线程运行浏览器的UI线程。这不会引起 CefDoMessageLoopWork()和 CefRunMessageLoop()的调用。. CefInitialize() 和CefShutdown() 应该在应用程序的主线程调用。 需要自己提供机制与应用程序主线程通信。

6. CefSettings

CefSettings结构允许Cef配置应用程序类型。以下列出通用的成员:

  • single_process 设置为true将为浏览器和渲染使用单进程。也可配置使用单个进程的命令行开关。
  • browser_subprocess_path 子进程的单个执行体路径,
  • multi_threaded_message_loop为true表示浏览器进程的消息循环以单线程运行。
  • command_line_args_idsabled为true表示禁用使用标准的CEF和Chrominum命令行参数的浏览器进程配置的特性。
  • cache_path缓存数据保存在磁盘上,如果为空,内存缓存会被某些特性使用,临时磁盘缓存会被其他地方使用。如果不为空,如HTML5本地存储数据库会跨域。
  • locale locale字符串会传递给blink,默认为en-US
  • log_file为debuglog文件路径
  • log_severity日志等级
  • resources_dir_path资料的目录路径。即cef.pak或devtools_resources.pak文件的保存路径
  • locales_dir_path
  • locales_dir_path locales的保存路径
  • remote_debugging_port远程调试端口。范围在1024~65535

     

7.CefBrowser和CefFrame

CefBrowser和CefFrame对象用于向浏览器发送命令和接受回调函数的状态信息。每个CerBrowser对象有一个主CefFrame对象描述主窗口。有零个和多个描述子窗口。例如:一个浏览器加载两个窗口会有三个CefFrame对象,一个是顶层窗口,两个子窗口。

在主窗口中加载一个URL:
browser->GetMainFrame()->LoadURL(some_url);

调用浏览的返回按钮:
browser->GoBack();

获取主窗口的HTML内容

class Visitor : public CefStringVisitor {

public: Visitor() {}

virtual void Visit(const CefString& string) OVERRIDE { // Do something with |string|... }

IMPLEMENT_REFCOUNTING(Visitor);

};

browser->GetMainFrame()->GetSource(new Visitor());

 CefBrowser和CefFrame对象分别存在浏览进程和渲染进程中。在浏览进程中可通过CefBrowser::GetHoset()函数控制主机行为,如获取窗口句柄:

CefWindowHandle window_handle = browser->GetHost()->GetWindowHandle();

8.CefApp

CefApp接口提供特殊进程回调的访问。重要的回调包括:
OnBeforeCommandLineProcessing 以编程的方式设置命令行
OnRegisterCustomSchemes 提供一个机会自定义主题
GetBrowserProcessHandler 指定浏览进程及包括 OnContextInitialized() 特定功能的处理者
GetRenderProcessHandler 渲染进程的处理者,包括JavaScript关联的回调和进程消息

9.CefClient 

 CefClient接口提供了浏览器实例的特定回调。一个CefClient实例可以被多个浏览器共享。重要的回调包括:
浏览器生命周期,上下文菜单,对话框,显示通知,拖拽事件,焦点事件,键盘事件的处理者
OnProcessMessageReceived 从渲染进程中发来的IPC消息的接受。 

10.浏览器生命周期

 Browser Life Space 以调用 CefBrowserHost::CreateBrowser()或CefBrowserHost::CreateBrowserSync()函数开始。 方便执行逻辑,包括CefBrowserProcessHandler::OnContextInitialized()或像WM_CREATE消息处理的调用。

CefLifeSpaceHandler类提供了管理浏览器生命周期的回调。

  • OnAfterCreated() 在浏览器对象被创建后立即调用,主应用程序通常用这个函数保存浏览器对象的引用,如:
    void MyClient::OnAfterCreated(CefRefPtr<CefBrowser> browser) {
      // Must be executed on the UI thread.
      REQUIRE_UI_THREAD();
      // Protect data members from access on multiple threads.
      AutoLock lock_scope(this);  // Deprecated -- see the “Threads” section.
    
      if (!m_Browser.get())   {
        // Keep a reference to the main browser.
        m_Browser = browser;
        m_BrowserId = browser->GetIdentifier();
      }
    
      // Keep track of how many browsers currently exist.
      m_BrowserCount++;
    }
  • CefBrowserHost::CloseBrowser() 销毁浏览进程 如:browser->GetHost()->CloseBrowser(false)
    如果浏览器是其他窗口的父窗口,那么这个关闭事件会引起父窗口的系统函数调用。那父窗口需要调用 CloseBrowser(false) 并等待第二个系统调用的关闭事件来指示浏览进程允许关闭。
    如果关闭通过Javascript事件或DoClose()回调函数处理,那第二个系统关闭事件就不会被发送。
    IsClosing()测试是否关闭,如果是第一次的系统关闭事件就返回false,每二次返回true; 
    第一个系统关闭事件是在窗口的WndProc函数中处理的
    case WM_CLOSE:

      if (g_handler.get() && !g_handler->IsClosing()) {
        CefRefPtr<CefBrowser> browser = g_handler->GetBrowser();
        if (browser.get()) {
          // Notify the browser window that we would like to close it. This will result in a call to 
          // MyHandler::DoClose() if the JavaScript ‘onbeforeunload‘ event handler allows it.
          browser->GetHost()->CloseBrowser(false);
    
          // Cancel the close.
          return 0;
        }
      }
    
      // Allow the close.
      break;
    
    case WM_DESTROY:
      // Quitting CEF is handled in MyHandler::OnBeforeClose().
      return 0;
    }
  • DoClose() 设置m_blsClosing标识并设置第二次系统关闭事件为false

    bool MyClient::DoClose(CefRefPtr<CefBrowser> browser) {
      // Must be executed on the UI thread.
      REQUIRE_UI_THREAD();
      // Protect data members from access on multiple threads.
      AutoLock lock_scope(this);
    
      // Closing the main window requires special handling. See the DoClose()
      // documentation in the CEF header for a detailed description of this
      // process.
      if (m_BrowserId == browser->GetIdentifier()) {
        // Notify the browser that the parent window is about to close.
        browser->GetHost()->ParentWindowWillClose();
    
        // Set a flag to indicate that the window close should be allowed.
        m_bIsClosing = true;
      }
    
      // Allow the close. For windowed browsers this will result in the OS close
      // event being sent.
      return false;
    }
  • OnBeforeClose 在接受第二次OS关闭事件之前需要调用OnBeforeCloseb函数释放浏览器进程的引用。

CEF3研究(二)