CEF(Chromium Embedded Framework)下载以及编译目的为了后续与DuiLib相结合
文章目录
- 1、CEF的介绍
- 1.1、概述
- 2、CEF的作用
- 3、CEF的下载和编译
- 3.1、基本文件结构
- 3.2、发布文件目录结构
- 3.3、必需组件
- 3.4、可选组件
- 3.4.1、本地化资源
- 3.4.2、其他资源
- 3.4.3、Direct3D 支持
- 3.5.4、ANGLE支持
- 3.4.5、SwANGLE 支持
- 3、编译libcef_dll_wrapper
- 4、CEF结构
- 4.1、 CEF进程和窗口之间的结构关系
- 4.2、 Renderer进程的实现结构
- 4.3、browser进程的实现结构
- 4.4、CEF多进程和多线程
- 4.4.1、 进程
- 4.4.2、 线程
- 4.5、网页嵌入应用程序代码构成和实例
- 4.5.1、 入口函数
- 4.5.2、CEF单实例进程
- 4.5.3、主子进程的模式
1、CEF的介绍
Chromium Embedded Framework(CEF) 是一个开源软件框架,用于在另一个应用程序中嵌入Chromium web浏览器。这使开发人员能够向其应用程序中添加web浏览功能,并能够使用HTML、CSS和JavaScript创建应用程序的用户界面(或只是其中的一部分)。
CEF在Linux、macOS和Windows上运行。它有许多语言绑定,包括C、C++、Go、Java和Python。
1.1、概述
Chromium嵌入式框架有两个版本:CEF 1和CEF 3。Chromium Content API出现后,CEF 2的开发被放弃。
CEF 1是基于Chromium WebKit API的单进程实现。它不再得到积极开发或支持。
CEF 3是基于Chromium Content API的多进程实现,其性能类似于Google Chrome。它使用异步消息传递在主应用程序进程和一个或多个渲染进程(Blink+V8 JavaScript引擎)之间进行通信。它支持内部(PDF查看器)或外部可加载的PPAPI插件和扩展。不支持单进程运行模式,但仍存在;当前仅用于调试目的。
2019年3月16日,CEF 版本号随着 CEF 73.1.3 + g46cf800 + chromium-73.0.3683.75的发布而改变。之前在2019年3月14日发布的版本是 CEF 3.3683.1920.g9f41a27。这两个版本都是基于 Chromium 73.0.3683.75,但是新版本编号的主要编号与它所基于的 Chromium 主要版本号相同。
CEF附带了一个名为CefClient的示例应用程序,该应用程序使用WinAPI、Cocoa或GTK(取决于平台)用C**++编写,并包含各种功能的演示。较新版本包括一个名为CefSimple的示例应用程序,该应用程序以及附带的教程演示了如何使用CEF 3**创建简单应用程序。
文档可以在位于include目录的头文件和 wiki页面上找到。
2、CEF的作用
CEF全称Chromium Embedded Framework,是一个基于Google Chromium 的开源项目。Google Chromium项目主要是为Google Chrome应用开发的,而CEF的目标则是为第三方应用提供可嵌入浏览器支持。CEF作用是在客户端嵌入网页界面。
- 嵌入一个兼容HTML5的浏览器控件到一个已经存在的本地应用。
- 创建一个轻量化的壳浏览器,用以托管主要用Web技术开发的应用。
- 有些应用有独立的绘制框架,使用CEF对Web内容做离线渲染。
- 使用CEF做自动化Web测试。
3、CEF的下载和编译
首先CEF的所有版本: 所有版本。
获取更多:
CEF自动构建了多个平台多个版本,这里选择Windows 64位平台的Standard Distribution文件。我下载的是这个版本: CEF下载。
解压出来里面有这些文件(build)是我自己创建的:
不同平台拥有共同的结构,介绍一下Standard Distribution版本的文件夹结构:
- cmake: 包含所有目标共享的CMake配置文件。
- Debug: 包含 libcef.dll、 libcef.lib 和构建运行基于 CEF 的应用程序所需的其他组件的调试版本。默认情况下,这些文件应该放在与可执行文件相同的目录中,并作为构建过程的一部分复制到那里。CEF动态库(libcef.dll on Windows, libcef.so on Linux, “Chromium Embedded Framework.framework” on OS X)
- include: 包含所有必需的CEF头文件。
- libcef_dll: 包含libcef_dll_wrapper静态库的源代码,所有使用CEF C++API的应用程序都必须链接该库。
- Release: 同Debug。包含 libcef.dll、 libcef.lib 和其他需要构建并运行基于CEF 的应用程序的发布版本
- Resources: 包含 libcef.dll 所需的资源
- tests: 演示CEF的用法demo及测试用例等。
每个二进制压缩包里包含一个README.txt文件和一个LICENSE.txt文件,README.txt用以描述平台相关的细节,而LICENSE.txt包含CEF的BSD版权说明。如果你发布了基于CEF的应用,则应该在应用程序的某个地方包含该版权声明。
3.1、基本文件结构
├─cmake
├─Debug
├─include
│ ├─base
│ │ └─internal
│ ├─capi
│ │ ├─test
│ │ └─views
│ ├─internal
│ ├─test
│ ├─views
│ └─wrapper
├─libcef_dll
│ ├─base
│ ├─cpptoc
│ │ ├─test
│ │ └─views
│ ├─ctocpp
│ │ ├─test
│ │ └─views
│ └─wrapper
├─Release
├─Resources
│ └─locales
└─tests
├─cefclient
│ ├─browser
│ ├─common
│ ├─renderer
│ └─resources
│ ├─extensions
│ │ └─set_page_color
│ └─win
├─cefsimple
│ └─res
├─ceftests
│ ├─extensions
│ ├─resources
│ │ ├─net
│ │ │ └─data
│ │ │ └─ssl
│ │ │ └─certificates
│ │ └─win
│ └─views
├─gtest
│ ├─include
│ │ └─gtest
│ ├─src
│ └─teamcity
│ ├─include
│ └─src
└─shared
├─browser
├─common
├─renderer
└─resources
-
cmake:包含所有目标共享的CMake配置文件
-
Debug:包含构建和运行基于CEF的应用程序的调试版本所需的libcef.dll、libcef.lib和其他组件。默认情况下,这些文件应该与可执行文件放在同一目录中,并将作为构建过程的一部分复制到那里。
-
include:包含所有必需的CEF头文件。
-
libcef_dll:包含libcef_dll_wrapper静态库的源代码,所有使用CEF C++API的应用程序都必须链接该库。
-
Release:包含libcef.dll、libcef.lib和其他必需的组件构建并运行基于CEF的应用程序的发布版本。通过默认情况下,这些文件应与可执行文件,并将作为构建过程的一部分复制到那里。
Resources:包含libcef.dll所需的资源。默认情况下,这些文件应与libcef…dll放在同一目录中,并将作为构建过程的一部分复制到那里。
-
tests/ 演示 CEF 用法的测试目录。
-
cefclient:包含配置为使用此发行版中的文件生成的 cefclient 示例应用程序。此应用程序演示了各种 CEF 功能。
-
cefsimple:包含配置为使用此发行版中的文件生成的 cefsimple 示例应用程序。此应用程序演示了创建浏览器窗口所需的最少功能。
-
ceftests:包含执行CEF API的单元测试。
-
gtest:包含ceftests目标使用的Google C++测试框架。
-
shared:包含由cefclient和ceftests目标共享的源代码。
使用cmake编译,我这里使用的是Visual Studio 2019编译,x64版本:
一共有7个项目:
- ALL_BUILD与ZERO_CHECK:是cmake自动生成的辅助工程。
- cef_gtest和ceftests:都是测试模块
- cefclient:一个包含CEF各种API演示的浏览器程序Demo。
- cefsimple:一个简单的CEF浏览器程序Demo。
- libcef_dll_wrapper:对libcef库的C++代码封装。上述cefclient与cefsimple都会用它。
等待一会儿,然后程序就执行起来了,默认打开的是谷歌首页,如果打开的空白,是因为无法访问谷歌导致的。
可以直接在VS中搜索www.google.com去更改代码,发现它在cefclient-browser-main_context_impl.cc文件里,把它改为www.baidu.com再运行就正常了。
cefsimple同理,在cefsimple->simpleapp.cc里:
url = command_line->GetSwitchValue("url");
if (url.empty())
url = "http://www.baidu.com";
3.2、发布文件目录结构
即发布之后的可执行文件所在目录含有的文件:
│ chrome_100_percent.pak
│ chrome_200_percent.pak
│ chrome_elf.dll
│ d3dcompiler_47.dll
│ debug.log
│ icudtl.dat
│ libcef.dll
│ libEGL.dll
│ libGLESv2.dll
│ resources.pak
│ snapshot_blob.bin
│ tree.txt
│ v8_context_snapshot.bin
│ vk_swiftshader.dll
│ vk_swiftshader_icd.json
│ vulkan-1.dll
│
└─locales
af.pak
...
zh-CN.pak
3.3、必需组件
没有它们,CEF将无法运作。
- libcef.dll: CEF核心库。
- chrome_elf.dll: 崩溃报告库。
- icudtl.dat: Unicode支持数据。
- snapshot_blob.bin: V8快照数据。
- v8_context_snapshot.bin: V8快照数据。
3.4、可选组件
以下组件是可选的。如果它们丢失,CEF将继续运行,但任何相关功能都可能损坏或禁用。
3.4.1、本地化资源
使用CefSettings.pack_loading_disabled可以完全禁用区域设置文件加载。可以使用CefSettings.locales_dir_path自定义区域设置目录路径。
locales/:包含CEF、Chromium和Blink使用的本地化资源的目录。根据CefSettings.locae值从该目录加载一个.pak文件。只需要分发已配置的区域设置。如果未配置区域设置,则将使用默认的区域设置“en-US”。如果没有这些文件,任意Web组件可能会显示错误。
3.4.2、其他资源
使用CefSettings.Pack_loading_disabled可以完全禁用包文件加载。可以使用CefSettings.resources_dir_path自定义资源目录路径。
- chrome_100_percent.pak。
- chrome_200_percent.pak。
- resources.pak。
这些文件包含CEF、Chromium和Blink使用的非本地化资源。如果没有这些文件,任意Web组件可能会显示错误。
3.4.3、Direct3D 支持
- d3dcompiler_47.dll。
支持GPU加速渲染HTML5内容,如2D画布、3D CSS和WebGL。如果没有此文件,当启用GPU加速时(大多数情况下为默认设置),上述功能可能会失败。建议使用此捆绑版本,而不是依赖可能旧的、未经测试的系统安装版本。
3.5.4、ANGLE支持
- libEGL.dll。
- libGLESv2.dll。
支持渲染HTML5内容,如2D画布、3D CSS和WebGL。如果没有这些文件,上述功能可能会失败。
3.4.5、SwANGLE 支持
- vk_swiftshader.dll。
- vk_swiftshader_icd.json。
- vulkan-1.dll。
支持使用SwiftShader的Vulkan库作为ANGLE的Vulken后端对HTML5内容(如2D画布、3D CSS和WebGL)进行软件渲染。如果没有这些文件,当GPU加速被禁用或不可用时,上述功能可能会失败。
来源于分发包内README.txt
3、编译libcef_dll_wrapper
其实最重要的libcef_dll_wrapper是不是发现还没编译,当然不是,我们在编译cefclient的时候,就顺带编译了。生成debug路径:
D:\cethree\cef_binary_105.3.37+g4445dc6+chromium-105.0.5195.102_windows64\build\libcef_dll_wrapper\Debug
release路径:
我们也可以查看项目,会发现这个库早已经在项目属性里设置好了。
4、CEF结构
4.1、 CEF进程和窗口之间的结构关系
一个浏览器有很多个CefBrowser窗口,这些窗口都是在Browser进程中创建。browser进程用来管理和处理回调函数消息。Renderer进程用来实现网页的渲染,每个renderer进程包含有一个主网页mainframe和多个子网页subframe。
4.2、 Renderer进程的实现结构
renderer程序继承CefApp和CefRenderProcessHandler类,在main函数中初始化。通过CefSettings.browser_subprocess_path配置render可执行程序路径。browser进程就会去启动这个进程去渲染网页。
4.3、browser进程的实现结构
browserapp要继承CefApp和CefBrowserProcessHandler类。实现browserapp的定义。同时要新建clienthandler类实现图中的回调函数接口类,用来处理拦截响应请求、管理生命周期、下载、显示加载、右键菜单等。在mian函数中初始化、启动消息循环。调用CefBrowserHost的静态方法创建browser窗口对象,在render进程的Frame中加载渲染内容。
4.4、CEF多进程和多线程
4.4.1、 进程
CEF3是多进程架构的,CEF3进程主要有一个Browser(浏览器)进程和多个Renderer(渲染)进程。Browser被定义为主进程,负责窗口管理,网络请求,网页管理 、网络交互。browser从服务器器请求到了响应,将html文本发送给Renderer 进程,render进程加载html,进行渲染,展示网页的内容;除此之外,Renderer进程还负责Js Binding和对Dom节点的访问。
Browser和Renderer进程可以通过发送异步消息进行双向通信。主应用程序很大,加载时间比较长,或者不能在非浏览器进程里使用,则宿主程序可使用独立的可执行文件去运行这些Renderer进程。这可以通过配置CefSettings.browser_subprocess_path变量做到。
4.4.2、 线程
Browser进程中包含如下主要的线程:
- TID_UI 线程是浏览器的主线程。如果应用程序在调用调用CefInitialize()时,传递CefSettings.multi_threaded_message_loop=false,这个线程也是应用程序的主线程。
- TID_IO 线程主要负责处理IPC消息以及网络通信。
- TID_FILE 线程负责与文件系统交互。
4.5、网页嵌入应用程序代码构成和实例
每个CEF3应用程序都是相同的结构
- 提供入口函数,用于初始化CEF、运行子进程执行逻辑或者CEF消息循环。
- 提供CefApp实现,用于处理进程相关的回调。
- 提供CefClient实现,用于处理Browser实例相关的回调。
- 执行CefBrowserHost::CreateBrowser()创建一个Browser实例,使用CefLifeSpanHandler管理Browser对象生命周期。
4.5.1、 入口函数
需要在程序的入口函数执行cef对象创建,初始化,命令行参数解析,CEF属性设置,和CEF消息循环开启等。CEF需要启动一个主进程来管理网页见面。这个主进程就是在man函数中启动,进入消息循环,直到程序结束,才退出main函数。
4.5.2、CEF单实例进程
单例进程模式就是CEF的启动,网页的打开都在:
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();
// Shut down CEF.
CefShutdown();
return 0;
}
4.5.3、主子进程的模式
主进程和子进程分开的模式,主进程运行browser进程,网页加载放在子进程render进程中。这是需要创建两个进程和两个主函数。
主进程程序的入口函数:
// Program entry-point function.
// 程序入口函数
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.
// 可选择性地实现CefApp接口
CefRefPtr<MyApp> app(new MyApp);
// Populate this structure to customize CEF behavior.
// 填充这个结构体,用于定制CEF的行为。
CefSettings settings;
// Specify the path for the sub-process executable.
// 指定子进程的执行路径
CefString(&settings.browser_subprocess_path).FromASCII(“/path/to/subprocess”);
// Initialize CEF in the main process.
// 在主进程中初始化CEF
CefInitialize(main_args, settings, app.get());
// Run the CEF message loop. This will block until CefQuitMessageLoop() is called.
// 执行消息循环,此时会堵塞,直到CefQuitMessageLoop()函数被调用。
CefRunMessageLoop();
// Shut down CEF.
// 关闭CEF
CefShutdown();
return 0;
}
子进程程序入口函数:
// Program entry-point function.
// 程序入口函数
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.
// 可选择性地实现CefApp接口
CefRefPtr<MyApp> app(new MyApp);
// Execute the sub-process logic. This will block until the sub-process should exit.
// 执行子进程逻辑,此时会堵塞直到子进程退出。
return CefExecuteProcess(main_args, app.get());
}
D玖: 赞
狼lold: 成功了,感谢大佬
2301_79794213: https://sourceforge.net/projects/mingw-w64/ 在files这个界面,你打开Tollchains targetting Win64,再打开Personal Builds,点入mingw builds,点 8.1.0,threads posix,再选seh
lwei2: 楼主,请教一下:我也自定义了一个类似你demo中的listItem,想动态创建多个listItem,应该怎么去实现呢?