重要的概念
在开发基于CEF3的应用程序前,需要理解一些重要的底层概念。
1. C++封装
libcef库使用C开发,导出的是一个C API。工程libcef_dll_wrapper是对这些C API的封装,与libcef库一起发布。这些c++代码通过工具translator自动生成。直接使用C API中以参看UsingTheCAPI部分。
2. 进程
CEF3基于多进程运行。主进程处理窗口的创建、UI及网络访问,主进程也叫浏览器进程。这个进程通常也是应用程序进程,大多数的逻辑运行在此进程下。渲染进程管理Blink渲染及JavaScript的运行。部分程序逻辑,如JavaScript的绑定、DOM的访问,也运行在渲染进程中。默认的进程模型会为每一个不同的跳转点(协议+域名,如http://www.baidu.com)创建一个新的渲染进程。在需要的时候,会创建一些其他类型的进程,如gpu进程。
默认情况下,主程序进程会被创建多次,作为非浏览器进程使用。即通过命令行传入不同标记给CefExecuteProcess函数实现非浏览器进程的创建。如果主程序的exe非常大,初始化需要很长的时间,或者主程序不适合作为非浏览器进程使用,那么可以提供一个单独的exe给子进程使用。这个可以通过配置项CefSettings.browser_subprocess_path实现。
CEF3创建的进程通过IPC技术进行交互。浏览器进程及渲染进程可以来回发送异步消息进行通信。渲染进程中的JavaScriptIntegration可以导出异步API,而这些API由浏览器进程进行具体处理(JavaScriptIntegration in the render process can expose asynchronous APIs that are handled in the browser process.)。
3. 线程
CEF3中每个进程都运行了多个线程。完整的线程列表可以查看枚举cef_thread_id_t。以下列举一些常用的线程。
- TID_UI
浏览器进程的主线程,如果使用CefSettings.multi_threaded_message_loop=false来调用CefInitialize(),则此线程同就应用程序主线程是同一个。 - TID_IO
浏览器进程用来处理IPC及网络消息的线程。 - TID_FILE*
浏览器进程用来与文件系统打交道的线程。阻塞操作应该在此线程或由客户程序创建的CefThread中运行。 - TID_RENDERER
渲染进程中的主线程。所有的Blink及V8交互必须在此线程中执行。
由于CEF的多线程特性,使用消息传递或锁定来保护数据成员不受多线程的访问是很重要的。CefPostTask系列函数支持在线程之间进行简单的异步消息传递。有关更多信息,请参见“Posting Tasks”部分。
当前线程可以使用CefCurrentlyOn()函数来验证。CEF样例程序中使用了以下辅助宏来帮助验证当前执行的是期望的线程类型。这此宏定义在include/wrapper/cef_helpers.h。
为了支持异步访问一块代码,CEF提供了base::Lock和base::AutoLock类型,定义在include/base/cef_lock.h中,示例如下:
4. 引用计数
CEF框架下所有的类实现继承于CefBase[RefCounted|Scoped]接口,所以的指针实例通过CefRefPtr进行管理,CefRefPtr是一个智能指针,通过调用AddRef()及Release()进行引用计数的管理。最简单的示例如下:
5. 字符串
CEF为字符串定义了自己的数据结构,原因如下:
- libcef库与宿主程序可能使用不同的runtime库进行堆内存的管理。所有对象,包括字符串,需要使用相同的runtime库进行内存的创建与释放。
- libcef库可以被编译支持不同字符类型的字符串(如UTF8,UTF16或者宽字符)。默认是UTF16,但你可以在cef_string.h修改,然后重新编译CEF来满足自己的需求。当使用宽字符时,要记住这会依赖具体的平台。
UTF16字符串的结构体:
然后,起个别名如下:
CEF提供了许多C API来操作字符串类型(mapped via #defines to the type-specific functions)。如下
- cef_string_set
- cef_string_clear
- cef_string_cmp
CEF也提供了一些函数用于不同编码(ASCII, UTF8, UTF16及宽字符)字符串间的转换。具体可查看cef_string.h及cef_string_types.h。
C++下使用CefString来处理CEF的字符串会很方便。CefString提供了到std::string(UTF8)及std::wstring(宽字符)的自动转换。也可被用于对结构体类型cef_string_t的赋值。
- 赋值或从std::string转换
- 赋值或从std::wstring转换
- 字符串编码为ASCII时,可使用FromASCII()
- 一些结构体,如CefSettings,有一些cef_string_t成员。CefString可以简化它的赋值操作。
6. 命令行参数
CEF3和Chromium的很多功能可以通过命令行参数来控制。这些参数的格式为"–some_argument[=optional_param]",这些参数通过CefExecuteProcess()和CefMainArgs结构体来传递给CEF。
- 在调用CefInitialize()前,可将CefSettings.command_line_args_disabled设置为true来禁用命令行参数。
- 在宿主程序中,可以通过重载函数CefApp::OnBeforeCommandLineProcessing()来传递命令行参数
- 可以通过重载函数CefBrowserProcessHandler::OnBeforeChildProcessLaunch()来向子进程传递特定的命令行参数
可以查看shared/common/client_switches.cc的注释获取更详细的信息
参考
https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-processes