CEF-概述和常用功能介绍(GeneralUsage翻译)

CEF(Chromium Embedded Framework)是一个基于Google Chromium的开源项目,为第三方应用提供嵌入式浏览器支持。CEF隔离Chromium的复杂代码并提供稳定API,支持多进程架构,提供GPU加速、远程调试等功能。本文档介绍了CEF的二进制包、源码编译、示例应用程序、重要概念(如进程、线程、字符串、命令行参数等)、应用程序布局和结构,以及网络请求处理等核心功能。
摘要由CSDN通过智能技术生成

1.介绍

https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md

翻译来自:cefutil

CEF全称Chromium Embedded Framework,是一个基于Google Chromium 的开源项目。Google Chromium项目主要是为Google Chrome应用开发的,而CEF的目标则是为第三方应用提供可嵌入浏览器支持。CEF隔离底层Chromium和Blink的复杂代码,并提供一套产品级稳定的API,发布跟踪具体Chromium版本的分支,以及二进制包。CEF的大部分特性都提供了丰富的默认实现,让使用者做尽量少的定制即可满足需求。在本文发布的时候,世界上已经有很多公司和机构采用CEF,CEF的安装量超过了100万。[CEF wikipedia]页面上有使用CEF的公司和机构的不完全的列表。CEF的典型应用场景包括:

  • 嵌入一个兼容HTML5的浏览器控件到一个已经存在的本地应用。

  • 创建一个轻量化的壳浏览器,用以托管主要用Web技术开发的应用。

  • 有些应用有独立的绘制框架,使用CEF对Web内容做离线渲染。

  • 使用CEF做自动化Web测试。

CEF3是基于Chomuim Content API多进程构架的下一代CEF,拥有下列优势:

  • 改进的性能和稳定性(JavaScript和插件在一个独立的进程内执行)。

  • 支持Retina显示器。

  • 支持WebGL和3D CSS的GPU加速。

  • 类似WebRTC和语音输入这样的前卫特性。

  • 通过DevTools远程调试协议以及ChromeDriver2提供更好的自动化UI测试。

  • 更快获得当前以及未来的Web特性和标准的能力。

本文档介绍CEF3开发中涉及到的一般概念。

2.开始

2.1.1.使用二进制包

CEF3的二进制包可以在这个页面下载。其中包含了在特定平台(Windows,Mac OS X 以及 Linux)编译特定版本CEF3所需的全部文件。不同平台拥有共同的结构:

  • cefclient

  • Debug

  • include

  • libcef_dll

  • Release

  • Resources

  • tools

每个二进制包包含一个README.txt文件和一个LICENSE.txt文件,README.txt用以描述平台相关的细节,而LICENSE.txt包含CEF的BSD版权说明。如果你发布了基于CEF的应用,则应该在应用程序的某个地方包含该版权声明。例如,你可以在"关于”和“授权"页面列出该版权声明,或者单独一个文档包含该版权声明。“关于”和“授权”信息也可以分别在CEF浏览器的"about:license"和"about:credits"页面查看。

基于CEF二进制包的应用程序可以使用每个平台上的经典编译工具。包括Windows平台上的Visual Studio,Mac OSX平台上的Xcode,以及Linux平台上的gcc/make编译工具链。CEF项目的下载页面包含了这些平台上编译特定版本CEF所需的编译工具的版本信息。在Linux上编译CEF时需要特别注意依赖工具链。

Tutorial Wiki页面有更多关于如何使用CEF3二进制包创建简单应用程序的细节。

2.1.2.从源码编译(Building from Source Code)

CEF可以从源码编译,用户可以使用本地编译系统或者像TeamCity这样的自动化编译系统编译。首先你需要使用svn或者git下载Chromium和CEF的源码。由于Chromium源码很大,只建议在内存大于4GB的现代机器上编译。编译Chromium和CEF的细节请参考BranchesAndBuilding页面。

2.1.3.示例应用程序(Sample Application)

cefclient是一个完整的CEF客户端应用程序示例,并且它的源码包含在CEF每个二进制发布包中。使用CEF创建一个新的应用程序,最简单的方法是先从cefclient应用程序开始,删除你不需要的部分。本文档中许多示例都是来源于cefclient应用程序。

2.1.4.重要概念(Important Concepts)

在开发基于CEF3的应用程序前,有一些重要的基础概念应该被理解。

2.1.4.1.C++ 封装(C++ Wrapper)

libcef 动态链接库导出 C API 使得使用者不用关心CEF运行库和基础代码。libcef_dll_wrapper 工程把 C API 封装成 C++ API同时包含在客户端应用程序工程中,与cefclient一样,源代码作为CEF二进制发布包的一部分共同发布。C/C++ API的转换层代码是由转换工具自动生成。UsingTheCAPI 页面描述了如何使用C API。

2.1.4.2.进程(Processes)

CEF3是多进程架构的。Browser被定义为主进程,负责窗口管理,界面绘制和网络交互。Blink的渲染和Js的执行被放在一个独立的Render 进程中;除此之外,Render进程还负责Js Binding和对Dom节点的访问。 默认的进程模型中,会为每个标签页创建一个新的Render进程。其他进程按需创建,例如管理插件的进程以及处理合成加速的进程等都是按需创建。

默认情况下,主应用程序会被多次启动运行各自独立的进程。这是通过传递不同的命令行参数给CefExecuteProcess函数做到的。如果主应用程序很大,加载时间比较长,或者不能在非浏览器进程里使用,则宿主程序可使用独立的可执行文件去运行这些进程。这可以通过配置CefSettings.browser_subprocess_path变量做到。更多细节请参考Application Structure一节。

CEF3的进程之间可以通过IPC进行通信。Browser和Render进程可以通过发送异步消息进行双向通信。甚至在Render进程可以注册在Browser进程响应的异步JavaScript API。 更多细节,请参考Inter-Process Communication一节。

通过设置命令行的--single-process,CEF3就可以支持用于调试目的的单进程运行模型。支持的平台为:Windows,Mac OS X 和Linux。

2.1.4.3.线程(Threads)

在CEF3中,每个进程都会运行多个线程。完整的线程类型表请参照cef_thread_id_t。例如,在Browser进程中包含如下主要的线程:

  • TID_UI 线程是浏览器的主线程。如果应用程序在调用调用CefInitialize()时,传递CefSettings.multi_threaded_message_loop=false,这个线程也是应用程序的主线程。

  • TID_IO 线程主要负责处理IPC消息以及网络通信。

  • TID_FILE 线程负责与文件系统交互。

由于CEF采用多线程架构,有必要使用锁和闭包来保证数据的线程安全语义。IMPLEMENT_LOCKING定义提供了Lock()和Unlock()方法以及AutoLock对象来保证不同代码块同步访问数据。CefPostTask函数组支持简易的线程间异步消息传递。更多信息,请参考Posting Tasks章节。

可以通过CefCurrentlyOn()方法判断当前所在的线程环境,cefclient工程使用下面的定义来确保方法在期望的线程中被执行。

#define REQUIRE_UI_THREAD()   ASSERT(CefCurrentlyOn(TID_UI));
#define REQUIRE_IO_THREAD()   ASSERT(CefCurrentlyOn(TID_IO));
#define REQUIRE_FILE_THREAD() ASSERT(CefCurrentlyOn(TID_FILE));

2.1.4.4.引用计数(Reference Counting)

所有的框架类从CefBase继承,实例指针由CefRefPtr管理,CefRefPtr通过调用AddRef()和Release()方法自动管理引用计数。框架类的实现方式如下:

class MyClass : public CefBase {
 public:
  // Various class methods here...

 private:
  // Various class members here...

  IMPLEMENT_REFCOUNTING(MyClass);  // Provides atomic refcounting implementation.
};

// References a MyClass instance
CefRefPtr<MyClass> my_class = new MyClass();

2.1.4.5.字符串(Strings)

CEF为字符串定义了自己的数据结构。主要是出于以下原因:

  • libcef包和宿主程序可能使用不同的运行时,对堆管理的方式也不同。所有的对象,包括字符串,需要确保和申请堆内存使用相同的运行时环境。

  • libcef包可以编译为支持不同的字符串类型(UTF8,UTF16以及WIDE)。默认采用的是UTF16,默认字符集可以通过更改cef_string.h文件中的定义,然后重新编译来修改。当使用宽字节集的时候,切记字符的长度由当前使用的平台决定。

UTF16字符串结构体示例如下:

typedef struct _cef_string_utf16_t {
  char16* str;  // Pointer to the string
  size_t length;  // String length
  void (*dtor)(char16* str);  // Destructor for freeing the string on the correct heap
} cef_string_utf16_t;

通过typedef来设置常用的字符编码。

typedef char16 cef_char_t;
typedef cef_string_utf16_t cef_string_t;

CEF提供了一批C语言的方法来操作字符串(通过#define的方式来适应不同的字符编码)

  • cef_string_set 对制定的字符串变量赋值(支持深拷贝或浅拷贝)。

  • cef_string_clear 清空字符串。

  • cef_string_cmp 比较两个字符串。

CEF也提供了字符串不同编码之间相互转换的方法。具体函数列表请查阅cef_string.h和cef_string_types.h文件。

在C++中,通常使用CefString类来管理CEF的字符串。CefString支持与std::string(UTF8)、std::wstring(wide)类型的相互转换。也可以用来包裹一个cef_string_t结构来对其进行赋值。

和std::string的相互转换:

std::string str = “Some UTF8 string”;

// Equivalent ways of assigning |str| to |cef_str|. Conversion from UTF8 will occur if necessary.
CefString cef_str(str);
cef_str = str;
cef_str.FromString(str);

// Equivalent ways of assigning |cef_str| to |str|. Conversion to UTF8 will occur if necessary.
str = cef_str;
str = cef_str.ToString();

和std::wstring的相互转换:

std::wstring str = “Some wide string”;

// Equivalent ways of assigning |str| to |cef_str|. Conversion from wide will occur if necessary.
CefString cef_str(str);
cef_str = str;
cef_str.FromWString(str);

// Equivalent ways of assigning |cef_str| to |str|. Conversion to wide will occur if necessary.
str = cef_str;
str = cef_str.ToWString();

如果是ASCII编码,使用FromASCII进行赋值:

const char* cstr = “Some ASCII string”;
CefString cef_str;
cef_str.FromASCII(cstr);

一些结构体(比如CefSettings)含有cef_string_t类型的成员,CefString支持直接赋值给这些成员。

CefSettings settings;
const char* path = “/path/to/log.txt”;

// Equivalent assignments.
CefString(&settings.log_file).FromASCII(path);
cef_string_from_ascii(path, strlen(path), &settings.log_file);

2.1.4.6.命令行参数(Command Line Arguments)

在CEF3和Chromium中许多特性可以使用命令行参数进行配置。这些参数采用--some-argument[=optional-param]形式,并通过CefExecuteProcess()和CefMainArgs结构(参考下面的应用资源布局章节)传递给CEF。在传递CefSettings结构给CefInitialize()之前,我们可以设置CefSettings.command_line_args_disabled为true来禁用对命令行参数的处理。如果想指定命令行参数传入主应用程序,实现CefApp::OnBeforeCommandLineProcessing()方法。更多关于如何查找已支持的命令行选项的信息,请查看client_switches.cpp文件的注释。

2.1.5.应用程序布局(Application Layout)

应用资源布局依赖于平台,有很大的不同。比如,在Mac OS X上,你的资源布局必须遵循特定的app bundles结构;Window与Linux则更灵活,允许你定制CEF库文件与资源文件所在的位置。为了获取到特定可以正常工作的示例,你可以从工程的下载页面下载到一个client压缩包。每个平台对应的README.txt文件详细说明了哪些文件是可选的,哪些文件是必须的。

2.1.5.1.Windows操作系统(Windows)

在Windows平台上,默认的资源布局将libcef库文件、相关资源与可执行文件放置在同级目录,文件夹结构大致如下:

Application/
    cefclient.exe  <= cefclient application executable 
    libcef.dll <= main CEF library 
    icudt.dll <= ICU unicode support library 
    ffmpegsumo.dll <= HTML5 audio/video support library 
    libEGL.dll, libGLESv2.dll, … <= accelerated compositing support libraries 
    cef.pak, devtools_resources.pak <= non-localized resources and strings 
    locales/
        en-US.pak, … <= locale-specific resources and strings 

使用结构体CefSettings可以定制CEF库文件、资源文件的位置(查看README.txt文件或者本文中CefSettings部分获取更详细的信息)。虽然在Windows平台上,cefclient项目将资源文件以二进制形式编译进cefclient.rc文件,但是改为从文件系统加载资源也很容易。

2.1.6.应用程序结构(Application Structure)

每个CEF3应用程序都是相同的结构

  • 提供入口函数,用于初始化CEF、运行子进程执行逻辑或者CEF消息循环。

  • 提供CefApp实现,用于处理进程相关的回调。

  • 提供CefClient实现,用于处理Browser实例相关的回调。

  • 执行CefBrowserHost::CreateBrowser()创建一个Browser实例,使用CefLifeSpanHandler管理Browser对象生命周期。

2.1.6.1.入口函数(Entry-Point Function)

像本文中进程章节描述的那样,一个CEF3应用程序会运行多个进程,这些进程能够使用同一个执行器或者为子进程定制的、单独的执行器。进程的执行从入口函数开始,示例cefclient_win.cc、cefclient_gtk.cc、cefclient_mac.mm分别对应Windows、Linux和Mac OS-X平台下的实现。

当执行子进程时,CEF将使用命令行参数指定配置信息,这些命令行参数必须通过CefMainArgs结构体传入到CefExecuteProcess函数。CefMainArgs的定义与平台相关,在Linux、Mac OS X平台下,它接收main函数传入的argc和argv参数值。

CefMainArgs main_args(argc, argv);

在Windows平台下,它接收wWinMain函数传入的参数:实例句柄(HINSTANCE),这个实例能够通过函数GetModuleHandle(NULL)获取。

CefMainArgs main_args(hInstance);

2.1.7.单一执行体(Single Executable)

当以单一执行体运行时,根据不同的进程类型,入口函数有差异。Windows、Linux平台支持单一执行体架构,Mac OS X平台则不行。

int main(int argc, char* argv[]) {
  // Structure for passing command-line arguments.
  // The definition of this structure is platform-specific.
  CefMainArgs main_args(argc, argv);

  // Optional implementation of the CefApp interface.
  CefRefPtr<MyApp> app(new MyApp);

  // Execute the sub-process logic, if any. This will either return immediately for the browser
  // process or block until the sub-process should exit.
  int exit_code = CefExecuteProcess(main_args, app.get());
  if (exit_code >= 0) {
    // The sub-process terminated, exit now.
    return exit_code;
  }

  // Populate this structure to customize CEF behavior.
  CefSettings settings;

  // Initialize CEF in the main process.
  CefInitialize(main_args, settings, app.get());

  // Run the CEF message loop. This will block until CefQuitMessageLoop() is called.
  CefRunMessageLoop();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在CEF中添加F12调用控制台窗口的功能,可以按照以下步骤进行操作: 1. 在你的CEF应用程序中,找到处理键盘事件的代码。这通常是在你的键盘事件处理函数中。 2. 在键盘事件处理函数中,检查按下的键是否为F12键。你可以使用相关的键码或键标识来判断。 3. 如果检测到按下的是F12键,你需要执行一个操作来显示控制台窗口。在CEF中,可以通过调用`CefDevToolsManager::ToggleDevTools`方法来实现。 示例代码(C++): ```cpp CefRefPtr<CefBrowser> browser; // 获取到当前的CEF浏览器实例 CefRefPtr<CefFrame> frame = browser->GetMainFrame(); CefRefPtr<CefDevToolsManager> devToolsManager = CefDevToolsManager::GetInstance(); devToolsManager->ToggleDevTools(frame); ``` 示例代码(Python): ```python browser = ... # 获取到当前的CEF浏览器实例 frame = browser.GetMainFrame() dev_tools_manager = cefpython.GetDevToolsManager() dev_tools_manager.ToggleDevTools(frame) ``` 4. 确保在你的应用程序中正确设置了CEF DevTools。这通常涉及到在初始化CEF时启用DevTools,并注册相应的消息处理函数。 示例代码(C++): ```cpp void InitializeCef() { CefSettings settings; // 其他CEF设置... settings.remote_debugging_port = 8088; // 启用远程调试端口 CefInitialize(settings, nullptr, nullptr, nullptr); CefRefPtr<CefMessageRouterBrowserSide> messageRouter = CefMessageRouterBrowserSide::Create(); // 添加其他消息处理器... CefDevToolsMessageHandler::Register(messageRouter); // 注册DevTools消息处理器 } ``` 示例代码(Python): ```python def InitializeCef(): settings = {...} # 其他CEF设置 settings.remote_debugging_port = 8088 # 启用远程调试端口 cefpython.Initialize(settings) message_router = cefpython.GetGlobalMessageRouter() # 添加其他消息处理器... cefpython.AddDevToolsMessageHandler(message_router) # 注册DevTools消息处理器 ``` 通过以上步骤,你就可以在CEF中添加F12调用控制台窗口的功能了。当用户按下F12键时,控制台窗口将会被显示出来,供开发人员进行调试和查看页面信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值