CefV8Handler
概述
- 允许在
C++
中定义JavaScript
可调用的函数或属性 - 当
JavaScript
调用绑定的C++
函数时,会触发Execute
方法的C++
实现
继承CefV8Handler并重写Execute
- 示例1
1 2 3 4 5 6 |
// CefV8Handler virtual bool Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) OVERRIDE; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
bool SimpleApp::Execute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) { ExecuteMap_t::const_iterator itr = m_mapEnlinkApis.find(name); if (itr == m_mapEnlinkApis.end()) return true; if (itr->second) (this->*(itr->second))(object, arguments, retval, exception); else ForwardExecute(name, object, arguments, retval, exception); return true; } void SimpleApp::ForwardExecute(const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) { assert(!g_instanceClient); CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext(); if (!context) return; CefRefPtr<CefFrame> frame = context->GetFrame(); if (!frame) return; int64 const frameId = frame->GetIdentifier(); std::wstring msgName(L"$"); msgName += name.ToWString(); msgName += L"@"; msgName += std::to_wstring(frameId); CefRefPtr<CefProcessMessage> spMsg = CefProcessMessage::Create(msgName); if (!spMsg) return; CefRefPtr<CefListValue> spMsgArgs = spMsg->GetArgumentList(); CefV8ValueListToMsgList(arguments, spMsgArgs); bool bIsOK = false; #if (CEF_VERSION_MAJOR > 62) bIsOK = CefSendFrameMessage(frame, PID_BROWSER, spMsg); #else CefRefPtr<CefBrowser> browser = context->GetBrowser(); if (browser) bIsOK = CefSendProcessMessage(browser, PID_BROWSER, spMsg); #endif retval = CefV8Value::CreateBool(bIsOK); } |
- 示例2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
class MyV8Handler : public CefV8Handler { public: virtual bool Execute( const CefString& name, // JavaScript 调用的函数名 CefRefPtr<CefV8Value> object, // JavaScript 的 'this' 对象 const CefV8ValueList& arguments, // 调用参数列表 CefRefPtr<CefV8Value>& retval, // 返回值 CefString& exception // 异常信息(可选) ) override { if (name == "myFunction") { // 处理逻辑 retval = CefV8Value::CreateString("Hello from C++!"); return true; } return false; } IMPLEMENT_REFCOUNTING(MyV8Handler); // 必须实现引用计数 }; |
注册到V8上下文
- 在
CefRenderProcessHandler::OnContextCreated
中绑定函数: - 示例1
1 2 3 4 5 6 7 8 9 10 11 12 |
void MyApp::OnContextCreated( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context ) { CefRefPtr<CefV8Handler> handler(new MyV8Handler()); CefRefPtr<CefV8Value> global = context->GetGlobal(); // 创建函数并绑定到 JavaScript 的 "myFunction" CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("myFunction", handler); global->SetValue("myFunction", func, V8_PROPERTY_ATTRIBUTE_NONE); } |
1 2 3 |
myFunction().then(result => { console.log(result); // 输出 "Hello from C++!" }); |
- 示例2
1 2 3 4 5 |
// from CefRenderProcessHandler virtual void OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) OVERRIDE; |
1 2 3 4 5 6 7 8 9 10 11 12 |
void SimpleApp::OnContextCreated(CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) { CefRefPtr<CefV8Value> window = context->GetGlobal(); CefRefPtr<CefV8Value> enlink = CefV8Value::CreateObject(nullptr, nullptr); for (ExecuteMap_t::const_iterator itr = m_mapEnlinkApis.begin(); (itr != m_mapEnlinkApis.end()); ++itr) { //DbgMsgBox(itr->first.c_str()); enlink->SetValue(itr->first, CefV8Value::CreateFunction(itr->first, this), V8_PROPERTY_ATTRIBUTE_READONLY); } window->SetValue("enlink", enlink, V8_PROPERTY_ATTRIBUTE_READONLY); } |
高级用法:异步操作与回调
- 异步操作与回调
arguments[0]
:
假设JavaScript
调用C++
函数时,第一个参数是回调函数(例如myAsyncFunction((result) => {...})
)CefV8Context
:表示当前 JavaScript 执行上下文,用于后续操作中安全访问V8
对象Enter()/Exit()
:V8
的上下文是线程相关的,必须显式进入上下文才能操作V8
对象(类似加锁)ExecuteFunction
:调用JavaScript
回调函数,传递参数args
第一个参数nullptr
表示回调中的this
指向全局对象
- 解析:
JS
调用C++
:JavaScript
调用C++
函数,并传入一个回调函数C++
保存回调:C++
将回调函数和上下文保存(通常存储到类的成员变量或异步任务队列中)- 异步操作:
C++
执行耗时操作(如网络请求、文件读写) - 触发回调:操作完成后,从保存的上下文中安全调用
JavaScript
回调,传递结果
1 2 3 4 5 6 7 8 9 10 |
// C++ 端保存回调函数 CefRefPtr<CefV8Value> callback = arguments[0]; CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext(); // 异步操作完成后触发回调 context->Enter(); CefV8ValueList args; args.push(CefV8Value::CreateString("Async Result")); callback->ExecuteFunction(nullptr, args); context->Exit(); |
-
关于线程安全
V8
上下文绑定到特定线程:必须确保回调在 原上下文所在的线程 中执行(通常是渲染进程的主线程)Enter()/Exit()
的必要性:V8
引擎非线程安全,操作V8
对象前必须进入正确的上下文
-
示例:
JavaScript
调用
1 2 3 4 |
// 调用 C++ 异步函数,传递回调 myAsyncFunction((result) => { console.log("Received result:", result); // 输出 "Async Result" }); |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
class MyV8Handler : public CefV8Handler { public: bool Execute(...) override { if (name == "myAsyncFunction") { // 保存回调和上下文 CefRefPtr<CefV8Value> callback = arguments[0]; CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext(); // 模拟异步操作(实际可能是网络请求) std::thread([=]() { // 异步操作完成 context->GetTaskRunner()->PostTask(CefCreateClosureTask( base::BindOnce(&MyV8Handler::InvokeCallback, this, context, callback) )); }).detach(); return true; } return false; } void InvokeCallback(CefRefPtr<CefV8Context> context, CefRefPtr<CefV8Value> callback) { context->Enter(); CefV8ValueList args; args.push(CefV8Value::CreateString("Async Result")); callback->ExecuteFunction(nullptr, args); context->Exit(); } IMPLEMENT_REFCOUNTING(MyV8Handler); }; |
高级用法:双向通信
JS
→C++
:通过上述CefV8Handler
C++
→JS
:使用ExecuteJavaScript
方法
1 |
browser->GetMainFrame()->ExecuteJavaScript("alert('Message from C++');", "", 0); |
注意事项
- 线程安全:
- 确保
V8
操作在渲染进程的 V8 线程(通常为TID_RENDERER
)
- 确保
- 上下文生命周期:
- 避免在上下文销毁后访问 V8 对象
- 返回值处理:
- 未设置
retval
会导致 JavaScript 收到undefined
- 未设置
CefRenderProcessHandler
概述
CefRenderProcessHandler
是一个关键的接口,用于控制渲染进程(Renderer Process
)的行为- 每个
CEF
应用都需要在渲染进程中实现此接口,以处理与JavaScript
交互、V8
上下文管理、进程间通信(IPC
)等任务
核心作用
- 渲染进程入口点:定义渲染进程初始化及事件响应
JavaScript
扩展:通过V8
上下文注入C++
函数或对象到JavaScript
- 生命周期管理:监听浏览器上下文的创建和销毁
- 进程间通信:处理来自浏览器进程(
Browser Process
)的IPC
消息
OnRenderThreadCreated
- 调用时机:渲染进程的主线程创建后调用
- 执行渲染进程的全局初始化(例如注册
IPC
消息处理)
1 2 |
void OnRenderThreadCreated( CefRefPtr<CefListValue> extra_info) override; |
OnBrowserCreated
/ OnBrowserDestroyed
- 调用时机:浏览器实例在渲染进程中创建或销毁时触发
- 管理浏览器实例相关的资源
1 2 3 4 5 |
void OnBrowserCreated( CefRefPtr<CefBrowser> browser) override; void OnBrowserDestroyed( CefRefPtr<CefBrowser> browser) override; |
OnContextCreated
/ OnContextReleased
- 调用时机:
V8
上下文(JavaScript
执行环境)创建或销毁时触发 - 在
OnContextCreated
中注册C++
到JavaScript
的绑定(通过CefV8Handler
)
1 2 3 4 5 6 7 8 9 |
void OnContextCreated( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) override; void OnContextReleased( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) override; |
OnProcessMessageReceived
- 调用时机:收到来自浏览器进程或其他渲染进程的
IPC
消息 - 处理跨进程通信(例如传递数据、触发
JavaScript
回调)
示例
- 继承
CefRenderProcessHandler
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
class MyRenderProcessHandler : public CefRenderProcessHandler { public: // 重写关键方法 void OnContextCreated( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefV8Context> context) override { // 注册 JavaScript 绑定 CefRefPtr<CefV8Handler> handler(new MyV8Handler()); CefRefPtr<CefV8Value> global = context->GetGlobal(); global->SetValue("myFunction", CefV8Value::CreateFunction("myFunction", handler), V8_PROPERTY_ATTRIBUTE_NONE); } IMPLEMENT_REFCOUNTING(MyRenderProcessHandler); }; |
- 在
CefApp
中返回Handler
1 2 3 4 5 6 7 8 |
class MyApp : public CefApp { public: CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override { return new MyRenderProcessHandler(); } IMPLEMENT_REFCOUNTING(MyApp); }; |
怎么处理 IPC 消息
- 定义消息名称
- 在
C++
中定义消息的唯一标识符(双方进程需一致):
- 在
1 2 |
// 定义消息名称(需唯一) const std::string kMyMessage = "my_ipc_message"; |
JavaScript
发送消息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// 方法1:使用内置的 cefQuery(需启用 Web 安全域) window.cefQuery({ request: 'my_data_request', onSuccess: (response) => console.log("Success:", response), onFailure: (error, code) => console.error("Error:", error) }); // 方法2:通过自定义绑定(推荐) // 假设已通过 CefV8Handler 绑定了一个函数 sendIPCMessage sendIPCMessage({ action: "get_data", params: { id: 42 } }, (response) => { console.log("Received:", response); }); |
- 创建自定义
V8
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// MyV8Handler.cpp bool MyV8Handler::Execute( const CefString& name, CefRefPtr<CefV8Value> object, const CefV8ValueList& arguments, CefRefPtr<CefV8Value>& retval, CefString& exception) { if (name == "sendIPCMessage") { // 参数1:消息内容(JSON 字符串) // 参数2:JavaScript 回调函数 CefString message = arguments[0]->GetStringValue(); CefRefPtr<CefV8Value> callback = arguments[1]; // 创建进程消息 CefRefPtr<CefProcessMessage> msg = CefProcessMessage::Create(kMyMessage); // 将数据和回调保存到消息中 CefRefPtr<CefListValue> args = msg->GetArgumentList(); args->SetString(0, message); args->SetInt(1, callback->GetHash()); // 使用哈希标识回调 // 发送到浏览器进程 CefV8Context::GetCurrentContext()->GetBrowser()->SendProcessMessage(PID_BROWSER, msg); retval = CefV8Value::CreateBool(true); return true; } return false; } |
- 注册
JavaScript
函数- 在
CefRenderProcessHandler::OnContextCreated
中绑定函数:
- 在
1 2 3 4 5 |
void MyRenderProcessHandler::OnContextCreated(...) { CefRefPtr<CefV8Handler> handler(new MyV8Handler()); CefRefPtr<CefV8Value> func = CefV8Value::CreateFunction("sendIPCMessage", handler); context->GetGlobal()->SetValue("sendIPCMessage", func, V8_PROPERTY_ATTRIBUTE_NONE); } |
- 浏览器进程:处理消息并返回响应
- 在浏览器进程的
CefClient
子类中重写OnProcessMessageReceived
:
- 在浏览器进程的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// MyBrowserClient.cpp bool MyBrowserClient::OnProcessMessageReceived( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { if (message->GetName() == kMyMessage) { CefRefPtr<CefListValue> args = message->GetArgumentList(); CefString json_data = args->GetString(0); int callback_hash = args->GetInt(1); // 解析 JSON 数据(需自行实现或使用第三方库) // 假设解析出 action 和 params std::string action = parse_action(json_data); int id = parse_id(json_data); // 处理业务逻辑(例如查询数据库) std::string response = "Processed: ID=" + std::to_string(id); // 返回响应到渲染进程 CefRefPtr<CefProcessMessage> response_msg = CefProcessMessage::Create(kMyMessage); CefRefPtr<CefListValue> response_args = response_msg->GetArgumentList(); response_args->SetString(0, response); response_args->SetInt(1, callback_hash); browser->SendProcessMessage(PID_RENDERER, response_msg); return true; } return false; } |
- 渲染进程:接收浏览器进程的响应并触发
JS
回调- 在
CefRenderProcessHandler::OnProcessMessageReceived
中处理:
- 在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
// MyRenderProcessHandler.cpp bool MyRenderProcessHandler::OnProcessMessageReceived( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefProcessId source_process, CefRefPtr<CefProcessMessage> message) { if (message->GetName() == kMyMessage) { CefRefPtr<CefListValue> args = message->GetArgumentList(); CefString response = args->GetString(0); int callback_hash = args->GetInt(1); // 查找保存的回调函数(需维护一个回调映射表) CefRefPtr<CefV8Value> callback = GetCallbackByHash(callback_hash); if (callback && callback->IsFunction()) { CefRefPtr<CefV8Context> context = CefV8Context::GetCurrentContext(); context->Enter(); CefV8ValueList callback_args; callback_args.push(CefV8Value::CreateString(response)); callback->ExecuteFunction(nullptr, callback_args); context->Exit(); } return true; } return false; } |
- 维护回调映射表
1 2 3 4 5 6 7 8 9 |
// 全局存储回调(实际项目应使用线程安全容器) std::map<int, CefRefPtr<CefV8Value>> callback_map; // 保存回调(在发送消息时) int hash = callback->GetHash(); callback_map[hash] = callback; // 在收到响应后清除回调(避免内存泄漏) callback_map.erase(hash); |
高级优化
- 使用
Promise
封装- 在
JavaScript
中提供更现代的API
:
- 在
1 2 3 4 |
// 示例:JS 调用 sendIPCMessageAsync({ action: 'get_data' }) .then(response => console.log(response)) .catch(error => console.error(error)); |
- 二进制数据传输
- 通过
CefSharedMemoryRegion
传递大型二进制数据(如图像、文件)
- 通过
- 多进程协同
- 处理多个渲染进程(如多个浏览器标签页)的通信隔离
CefLoadHandler
概述
- 是一个用于监控页面加载过程的核心接口
- 通过实现该接口,开发者可以捕获浏览器加载页面时的关键事件(如开始加载、加载完成、加载失败等),从而实现对页面生命周期的精细控制
核心作用
- 页面加载状态跟踪:实时获取页面加载进度和状态
- 错误处理:捕获加载失败事件(如网络错误、证书问题等)
- 资源拦截:管理资源(如
CSS
、JS
、图片)的加载行为 - 生命周期回调:在页面加载的关键节点执行自定义逻辑
OnLoadingStateChange
- 触发时机:页面开始加载或结束加载时
isLoading
:是否正在加载canGoBack
/canGoForward
:浏览器导航按钮状态
1 2 3 4 5 |
void OnLoadingStateChange( CefRefPtr<CefBrowser> browser, bool isLoading, bool canGoBack, bool canGoForward) override; |
- 比如更新
UI
1 2 3 4 5 6 7 8 |
void MyLoadHandler::OnLoadingStateChange(...) { if (isLoading) { ShowLoadingSpinner(); // 显示加载动画 } else { HideLoadingSpinner(); // 隐藏加载动画 UpdateNavButtons(canGoBack, canGoForward); // 更新导航按钮 } } |
OnLoadStart
- 触发时机:页面或子框架(如
iframe
)开始加载时 frame
:加载的框架(主框架或子框架)transition_type
:导航类型(如用户点击链接、前进/后退)
1 2 3 4 |
void OnLoadStart( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, TransitionType transition_type) override; |
OnLoadEnd
- 触发时机:页面或子框架加载完成时(无论成功或失败)
httpStatusCode
:HTTP
状态码(如200
、404
)
1 2 3 4 |
void OnLoadEnd( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, int httpStatusCode) override; |
- 比如注入自定义
JavaScript
或统计加载耗时
1 2 3 4 5 |
void MyLoadHandler::OnLoadEnd(...) { if (frame->IsMain()) { // 仅主框架 frame->ExecuteJavaScript("console.log('Page loaded!');", "", 0); } } |
OnLoadError
- 触发时机:页面加载失败时
errorCode
:错误类型(如网络错误、证书错误)failedUrl
:加载失败的URL
1 2 3 4 5 6 |
void OnLoadError( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, ErrorCode errorCode, const CefString& errorText, const CefString& failedUrl) override; |
- 比如显示自定义错误页面
1 2 3 4 5 |
void MyLoadHandler::OnLoadError(...) { if (errorCode == ERR_CONNECTION_TIMED_OUT) { frame->LoadURL("chrome://error/connection_timeout.html"); } } |
示例
- 继承
CefLoadHandler
1 2 3 4 5 6 7 8 |
class MyLoadHandler : public CefLoadHandler { public: // 重写需要的方法 void OnLoadingStateChange(...) override { /* ... */ } void OnLoadError(...) override { /* ... */ } IMPLEMENT_REFCOUNTING(MyLoadHandler); // 必须实现引用计数 }; |
- 将
Handler
附加到CefClient
- 在自定义的
CefClient
子类中返回CefLoadHandler
:
- 在自定义的
1 2 3 4 5 6 7 8 9 |
class MyClient : public CefClient { public: CefRefPtr<CefLoadHandler> GetLoadHandler() override { return my_load_handler_; // 返回自定义的 LoadHandler } private: CefRefPtr<MyLoadHandler> my_load_handler_ = new MyLoadHandler(); }; |
高级用法:拦截资源加载
- 通过
CefRequestHandler
的GetResourceRequestHandler
方法拦截请求:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
CefRefPtr<CefResourceRequestHandler> GetResourceRequestHandler( CefRefPtr<CefBrowser> browser, CefRefPtr<CefFrame> frame, CefRefPtr<CefRequest> request, bool is_navigation, bool is_download, const CefString& request_initiator, bool& disable_default_handling) override { // 拦截特定类型的资源(如广告) if (IsAdRequest(request->GetURL())) { return new AdBlockHandler(); // 返回自定义的拦截处理器 } return nullptr; } |
高级用法:加载性能监控
- 统计页面加载时间:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
class MyLoadHandler : public CefLoadHandler { private: std::chrono::time_point<std::chrono::steady_clock> load_start_time_; void OnLoadStart(...) override { if (frame->IsMain()) { load_start_time_ = std::chrono::steady_clock::now(); } } void OnLoadEnd(...) override { if (frame->IsMain()) { auto duration = std::chrono::steady_clock::now() - load_start_time_; double load_time = std::chrono::duration<double>(duration).count(); Log("Page loaded in " + std::to_string(load_time) + " seconds."); } } }; |
CefApp
概述
- 进程管理:标识当前进程类型(浏览器进程、渲染进程等)并分发对应的处理器
- 全局配置:通过
CefSettings
设置CEF
的全局参数(如缓存路径、日志级别) - 多进程通信:为不同进程提供处理接口(如
CefBrowserProcessHandler
和CefRenderProcessHandler
) - 命令行参数控制:通过
OnBeforeCommandLineProcessing
修改启动参数
OnBeforeCommandLineProcessing
- 用途:修改启动命令行参数(例如禁用沙箱、开启
GPU
加速)
1 2 3 |
void OnBeforeCommandLineProcessing( const CefString& process_type, CefRefPtr<CefCommandLine> command_line) override; |
1 2 3 4 5 6 7 8 |
void MyApp::OnBeforeCommandLineProcessing(...) { // 禁用沙箱(仅在开发调试时使用) if (process_type.empty()) { // 浏览器进程 command_line->AppendSwitch("no-sandbox"); } // 开启远程调试端口 command_line->AppendSwitchWithValue("remote-debugging-port", "9222"); } |
GetBrowserProcessHandler
- 用途:返回浏览器进程的处理器(仅在浏览器进程中调用)
1 2 3 |
CefRefPtr<CefBrowserProcessHandler> MyApp::GetBrowserProcessHandler() { return my_browser_handler_; // 返回自定义的浏览器进程处理器 } |
GetRenderProcessHandler
- 用途:返回渲染进程的处理器(仅在渲染进程中调用)
1 2 3 |
CefRefPtr<CefRenderProcessHandler> MyApp::GetRenderProcessHandler() { return my_render_handler_; // 返回自定义的渲染进程处理器 } |
进程类型判断
- 通过
process_type
参数区分当前进程:- 空字符串:浏览器进程(主进程)
- "
renderer
":渲染进程 - "
gpu-process
":GPU
进程 - "
utility
":工具进程
1 2 3 4 5 6 |
// 在 OnBeforeCommandLineProcessing 中判断进程类型 if (process_type.empty()) { // 当前是浏览器进程 } else if (process_type == "renderer") { // 当前是渲染进程 } |
示例代码
- 定义
CefApp
子类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
class MyApp : public CefApp, public CefBrowserProcessHandler, public CefRenderProcessHandler { public: // CefApp 接口 CefRefPtr<CefBrowserProcessHandler> GetBrowserProcessHandler() override { return this; // 返回自身(若实现 BrowserProcessHandler 逻辑) } CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override { return this; // 返回自身(若实现 RenderProcessHandler 逻辑) } void OnBeforeCommandLineProcessing(...) override { /* 略 */ } // CefBrowserProcessHandler 接口(浏览器进程) void OnContextInitialized() override { // 浏览器进程初始化完成 } // CefRenderProcessHandler 接口(渲染进程) void OnContextCreated(...) override { // 注册 JavaScript 绑定 } IMPLEMENT_REFCOUNTING(MyApp); // 必须实现引用计数 }; |
- 初始化
CEF
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
int main(int argc, char* argv[]) { // 初始化 CEF CefMainArgs args(argc, argv); CefSettings settings; // 配置全局参数 settings.no_sandbox = true; settings.multi_threaded_message_loop = true; settings.log_severity = LOGSEVERITY_DEBUG; // 创建 CefApp 实例 CefRefPtr<MyApp> app(new MyApp()); // 初始化并运行 CefInitialize(args, settings, app.get(), nullptr); CefRunMessageLoop(); // 启动消息循环 CefShutdown(); // 关闭 CEF return 0; } |
本文为原创文章,版权归Aet所有,欢迎分享本文,转载请保留出处!
你可能也喜欢
- ♥ cef:任务、IPC、网络相关04/30
- ♥ Windows进程通信相关03/10
- ♥ C++标准库_chrono03/28
- ♥ Macos编译x86_64相关一04/25
- ♥ 树总结相关07/26
- ♥ 大话数据结构_算法相关&&AVL&&B树相关02/20