首页 > 其他分享 >CEF 浏览器内核的嵌入与实例化

CEF 浏览器内核的嵌入与实例化

时间:2024-12-08 09:03:36浏览次数:7  
标签:CEF 浏览器 渲染 实例 CefBrowser 内核 进程

在实际的 CEF 浏览器应用开发中,如何高效地嵌入和实例化 CefBrowser 对象,如何管理浏览器的生命周期,以及如何实现浏览器进程和主程序进程之间的通信是至关重要的技术点。本节将深入探讨如何创建和管理 CefBrowser 实例,如何进行浏览器进程与主程序进程的通信,确保数据交互流畅且稳定。

1. 创建并管理 CefBrowser 实例

CefBrowser 实例是浏览器嵌入应用中的核心组件。每个 CefBrowser 对象代表一个浏览器窗口,可以加载和显示 Web 页面。创建和管理多个 CefBrowser 实例是一个需要精确控制的任务,因为每个浏览器实例不仅涉及到页面渲染,还可能影响到性能和资源管理。

1.1 浏览器进程初始化

为了初始化 CEF 浏览器,首先需要配置并启动 CEF 的主进程。主进程负责初始化应用并启动渲染进程,渲染进程负责处理浏览器中的 HTML 渲染、JavaScript 执行等操作。初始化过程分为以下几步:

  1. 初始化 CefSettings:CefSettings 是配置 CEF 的重要结构体,开发者可以通过修改 CefSettings 对象来控制 CEF 的行为,比如启用沙箱、安全设置、缓存配置等。

    CefSettings settings;
    settings.no_sandbox = false;  // 启用沙箱
    settings.multi_threaded_message_loop = true;  // 启用多线程消息循环
    CefInitialize(main_args, settings, app.get(), nullptr);
  2. 创建 CefBrowser 对象:通过 CefBrowserHost::CreateBrowser 方法,可以创建浏览器实例。此方法需要传入一个包含浏览器窗口信息的 CefWindowInfo 对象以及一个 CefClient 实例。CefClient 是一个实现了 CefLifeSpanHandlerCefRenderHandler 等接口的类,负责管理浏览器生命周期及与浏览器的交互。

    CefWindowInfo window_info;
    window_info.SetAsWindowless(0);  // 创建无边框窗口
    CefRefPtr<CefClient> client = new MyCefClient();
    CefBrowserSettings browser_settings;
    CefBrowserHost::CreateBrowser(window_info, client, "https://www.example.com", browser_settings, nullptr);
    • CefWindowInfo:设置窗口的参数,如窗口模式(无边框、透明等)。
    • CefClient:用户定义的客户端类,用于处理浏览器的事件和回调。
    • CefBrowserSettings:设置浏览器的相关属性,如 JavaScript 引擎、页面缓存等。
  3. 管理浏览器生命周期:在创建浏览器之后,开发者需要管理其生命周期。CefBrowser 对象有多种方法,如 CefBrowser::CloseBrowser 用于关闭浏览器窗口,CefBrowser::GetHost()->CloseBrowser(false) 用于销毁浏览器实例。通过 CefLifeSpanHandler 中的回调方法,开发者可以获取到浏览器窗口的关闭事件。

    class MyCefLifeSpanHandler : public CefLifeSpanHandler {
    public:
        void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
            // 浏览器创建完成后的处理逻辑
        }
        bool DoClose(CefRefPtr<CefBrowser> browser) override {
            // 浏览器关闭前的清理逻辑
            return false;
        }
    };
  4. 多个浏览器窗口管理:通过实例化多个 CefBrowser 对象,可以在同一个应用中同时显示多个浏览器窗口。每个 CefBrowser 都是独立的浏览器实例,具有自己的生命周期和状态。可以通过 CefClient 类来管理多个浏览器窗口的创建与销毁。

    CefRefPtr<MyCefClient> client1 = new MyCefClient();
    CefRefPtr<MyCefClient> client2 = new MyCefClient();
    
    CefBrowserHost::CreateBrowser(window_info, client1, "https://www.example1.com", browser_settings, nullptr);
    CefBrowserHost::CreateBrowser(window_info, client2, "https://www.example2.com", browser_settings, nullptr);
  5. 销毁浏览器实例:当一个 CefBrowser 实例不再需要时,可以通过调用 CefBrowser::GetHost()->CloseBrowser(true) 来销毁浏览器对象并释放资源。

1.2 浏览器进程和主程序进程的通信机制

CEF 基于 Chromium 浏览器内核的多进程架构,主程序进程和渲染进程通过一套有效的通信机制进行数据交换。为了实现浏览器与本地应用的数据交互,可以使用多种机制,包括 IPC(进程间通信)、消息队列、共享内存等。

在 CEF 中,主进程和渲染进程之间的通信一般是通过以下两种主要方式实现的:

  • IPC(进程间通信):主进程与渲染进程通过管道、套接字等机制进行通信。
  • Windows 消息队列:Windows 操作系统提供的消息机制,能够在进程间传递消息。
1.3 使用 IPC 管道实现主进程与渲染进程通信

IPC 是一种常见的进程间通信方式,可以使用管道(Pipe)、套接字(Socket)等技术实现主进程与渲染进程的数据交换。在 CEF 中,IPC 的实现基于 Chromium 自身的跨进程通信框架。

  1. CefMessageRouter:CEF 提供了 CefMessageRouter 类,允许主进程向渲染进程发送和接收消息。CefMessageRouter 能够将数据从浏览器窗口传递到主程序,并反向传递数据。

  2. 实现 IPC 机制:通过 CefMessageRouter 和自定义的消息路由器,主进程可以向渲染进程发送命令、请求等信息,渲染进程也可以通过响应机制返回结果。例如,开发者可以通过 IPC 传递自定义的 JavaScript 函数调用,并在主进程中处理。

    CefRefPtr<CefMessageRouter> message_router = CefMessageRouter::Create();
    message_router->AddHandler(new MyMessageHandler(), true);  // 添加消息处理器
    
    // 发送消息到渲染进程
    CefPostTask(TID_RENDERER, base::Bind(&SendMessageToRenderer));
  3. 消息路由器的使用:通过 CefMessageRouter,主进程和渲染进程可以实现双向通信。在渲染进程中,可以通过 CefBrowser::SendProcessMessage 向主进程发送消息。主进程可以通过自定义的 CefMessageRouterHandler 处理这些消息。

    // 渲染进程发送消息到主进程
    CefRefPtr<CefProcessMessage> message = CefProcessMessage::Create("custom_message");
    message->GetArgumentList()->SetString(0, "Hello, main process!");
    browser->GetMainFrame()->SendProcessMessage(PID_BROWSER, message);
1.4 使用消息队列实现浏览器与本地应用的数据交互

除了 IPC,Windows 的消息队列也可以用于实现主进程与渲染进程的通信。在 CEF 中,开发者可以利用 PostMessageSendMessage API 将数据从渲染进程传递给主程序。通过监听特定的消息,主程序可以接收到来自渲染进程的指令或数据。

  1. PostMessage 和 SendMessagePostMessage 会将消息放入消息队列,异步处理;SendMessage 会同步发送消息并等待处理结果。开发者可以根据需要选择合适的消息传递方式。

    HWND hwnd = ::FindWindow(NULL, L"MyCEFApp");
    PostMessage(hwnd, WM_USER + 1, (WPARAM)msg_data, 0);
  2. 消息处理:在主程序中,通过实现消息处理函数,可以接收到来自渲染进程的消息并执行相应的处理。

    LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
        if (msg == WM_USER + 1) {
            // 处理来自渲染进程的消息
            HandleMessageFromRenderer(wParam);
        }
        return DefWindowProc(hwnd, msg, wParam, lParam);
    }
  3. 窗口消息与进程间通信的结合:消息队列机制可以与 CEF 的进程间通信机制结合,进一步优化数据交互的灵活性。主程序可以通过消息队列管理多个浏览器窗口的通信,并根据需要执行不同的操作。

1.5 总结与最佳实践

在开发过程中,创建并管理多个 CefBrowser 实例以及实现浏览器进程和主程序进程之间的通信是一个至关重要的部分。结合 CEF 提供的多进程架构与 IPC 技术,开发者可以实现高效、稳定的浏览器内核嵌入。通过合理设计通信机制、消息传递方式和浏览器实例管理,可以确保浏览器应用的高性能和可扩展性。

在具体实践中,开发者应根据实际需求选择合适的通信方式,如 IPC 管道、消息队列等。同时,合理管理浏览器生命周期、处理错误和异常情况,也是开发中的重要任务。在此基础上,开发者可以实现丰富的功能和定制化需求,确保 CEF 浏览器应用能够满足各类场景的需求。

关于作者:

15年物联网开发、带过10-20人的团队,多次帮助公司从0到1完成项目开发,在TX等大厂都工作过。当下为退役状态,写此篇文章属个人爱好。本人10多年开发经验期间手机了很多开发课程等资料,需要可联系我

标签:CEF,浏览器,渲染,实例,CefBrowser,内核,进程
From: https://blog.csdn.net/u012263104/article/details/144299017

相关文章

  • Python Selenium 各浏览器驱动下载与配置使用(详细流程)
    1、安装pipinstallselenium2、浏览器驱动下载Chrome(google)浏览器驱动下载地址:http://chromedriver.storage.googleapis.com/index.html 或 https://sites.google.com/a/chromium.org/chromedriver/home. 下载地址:http://chromedriver.storage.googleapis.com/inde......
  • 您与该网站的连接不是私密连接,存在安全隐患,解决浏览器提示连接不安全的问题
    如果你只是普通访客,不用理睬,忽略即可。如果你是网站站上,请检查网站证书部署。当浏览器提示“您与该网站的连接不是私密连接,存在安全隐患”时,说明该网站的SSL证书存在问题,导致数据传输不安全。以下是一些解决方法:检查证书有效期:确认证书是否已过期。如果已过期,需要更新证......
  • Source Insight 导入linux内核源码
    参考https://www.cnblogs.com/joezh/p/13894145.html用法将脚本中的ABS_PATH="D:/si_code/linux-6.12/"路径换成在windows上可以访问的路径将源码完整编译一遍在源码目录下执行下面的脚本即可,最后会在当前目录下生成文件si_filelist_ARCH.txt,其中包含的是需要导入的文件列......
  • 【kernel】从 /proc/sys/net/ipv4/ip_forward 参数看如何玩转 procfs 内核参数
    本文的开篇,我们先从sysctl这个命令开始。sysctl使用sysctl是一个Linux系统工具,后台实际上是syscall,它允许用户查看和动态修改内核参数。#查看当前设置的所有内核参数sysctl-a#查看特定参数的值sysctlnet.ipv4.conf.all.forwarding#临时修改内核参数sysctlnet......
  • 监测各个核上cpu上的线程是内核线程还是用户线程,处于内核态还是用户态的方法
    一、背景这篇博客是对于之前的 内核模块注册调度的tracepoint的回调,逻辑里判断当前线程处于内核态还是用户态的方法-CSDN博客 的补充,在 内核模块注册调度的tracepoint的回调,逻辑里判断当前线程处于内核态还是用户态的方法-CSDN博客 里的方法,我们在那篇博客的最后提示了只......
  • node的事件循环和浏览器的事件循环有什么区别?
    Node.js和浏览器的事件循环虽然都是基于事件驱动的架构,但它们在实现和一些细节上有所不同。主要区别如下:1.I/O处理:浏览器:浏览器中的I/O操作主要依赖于WebAPIs(例如:fetch,XMLHttpRequest,setTimeout等)。浏览器负责管理这些API,并在操作完成后将相应的事件添加到事......
  • 纯js可定制的跨浏览器日期时间选择器插件
    Rome是一款纯js可定制的跨浏览器日期时间选择器插件。该日期时间选择器不依赖于jquery,但它依赖于moments.js。可以通过CSS文件来自定义该日期时间选择器的外观样式。在线预览 下载  安装可以通过Bower或nmp来安装该日期时间选择器插件。npminstall--saveromebower......
  • 防止浏览器记住密码
    一、问题引入客户要求登录时,不能被浏览器截取记录密码  二、问题分析问题的根源就在于浏览器会捕捉你的password的输入记录,以最后一次为节点进行存储。所以不管我们对password做什么处理,只要是password进行了输入,都会被拦截。三、解决方案使用css属性-webkit-text-securi......
  • 在设置keyup监听事件后按F5刷新和按浏览器中刷新键刷新有什么区别?
    在前端开发中,使用keyup监听事件后,按F5刷新和点击浏览器刷新按钮,虽然最终结果都是刷新页面,但在某些情况下会有一些细微的差别:1.触发事件的时机:F5(或Ctrl+R/Cmd+R):直接触发浏览器的刷新机制,并不会触发keyup事件。因为keyup事件是在按键释放时触发的,而按下F5并不会释放,而是......
  • Geolocation.getCurrentPosition()用来做什么的?在什么浏览器不受兼容?
    geolocation.getCurrentPosition()是一个JavaScriptAPI,用于获取用户的当前地理位置。它属于GeolocationAPI的一部分,允许Web应用程序访问用户的地理位置信息,前提是用户授予了权限。该方法异步地尝试获取用户的地理位置。成功获取位置后,会调用一个回调函数,并将一个Positio......