qt调用cef的Demo,实现js与C++之间的交互细节

想在 Qt 中集成 CEF (Chromium Embedded Framework) ,并且实现 JS 与 C++ 交互 ,本文是一个最小可运行的 Demo 示例

⚠️ 提示:

  • 这个 Demo 假设你已经下载并编译好了 CEF SDK,并且把头文件、库文件配置到 Qt 工程中。

  • 代码展示了 Qt 调用 CEF,创建一个简单的浏览器窗口,并实现 JS 调用 C++ 和 C++ 调用 JS 的交互。


1. main.cpp

复制代码
复制代码
#include <QApplication>
#include "cef_app_qt.h"
#include "cef_browser_widget.h"

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // 初始化 CEF
    CefEnableHighDPISupport();
    CefMainArgs main_args(argc, argv);
    CefRefPtr<CefAppQt> cefApp(new CefAppQt);

    int exit_code = CefExecuteProcess(main_args, cefApp, nullptr);
    if (exit_code >= 0) {
        return exit_code;  // 子进程
    }

    CefSettings settings;
    settings.no_sandbox = true;
    CefInitialize(main_args, settings, cefApp, nullptr);

    // 创建 Qt + CEF 的窗口
    CefBrowserWidget browser;
    browser.resize(800, 600);
    browser.show();

    int result = app.exec();

    // 关闭 CEF
    CefShutdown();
    return result;
}

2. cef_app_qt.h

复制代码
复制代码
#pragma once
#include "include/cef_app.h"

// 简单的 CefApp 派生类
class CefAppQt : public CefApp, public CefRenderProcessHandler {
public:
    CefAppQt() = default;

    CefRefPtr<CefRenderProcessHandler> GetRenderProcessHandler() override {
        return this;
    }

    // 处理渲染进程中 JS 与 C++ 的交互
    void OnContextCreated(CefRefPtr<CefBrowser> browser,
                          CefRefPtr<CefFrame> frame,
                          CefRefPtr<CefV8Context> context) override {
        CEF_REQUIRE_RENDERER_THREAD();

        // 注册 JS -> C++ 的函数
        CefRefPtr<CefV8Value> global = context->GetGlobal();
        CefRefPtr<CefV8Handler> handler = new JsHandler();
        global->SetValue("callCpp", CefV8Value::CreateFunction("callCpp", handler), V8_PROPERTY_ATTRIBUTE_NONE);
    }

private:
    class JsHandler : public CefV8Handler {
    public:
        JsHandler() = default;

        bool Execute(const CefString& name,
                     CefRefPtr<CefV8Value> object,
                     const CefV8ValueList& arguments,
                     CefRefPtr<CefV8Value>& retval,
                     CefString& exception) override {
            if (name == "callCpp") {
                if (arguments.size() > 0 && arguments[0]->IsString()) {
                    std::string msg = arguments[0]->GetStringValue();
                    qDebug("JS 调用了 C++,传递参数: %s", msg.c_str());

                    // 返回一个值给 JS
                    retval = CefV8Value::CreateString("C++ 已收到: " + msg);
                    return true;
                }
            }
            return false;
        }

        IMPLEMENT_REFCOUNTING(JsHandler);
    };

    IMPLEMENT_REFCOUNTING(CefAppQt);
};

3. cef_browser_widget.h

复制代码
复制代码
#pragma once
#include <QWidget>
#include "include/cef_browser.h"
#include "include/cef_client.h"

class CefBrowserWidget : public QWidget, public CefClient, public CefLifeSpanHandler {
    Q_OBJECT
public:
    CefBrowserWidget(QWidget* parent = nullptr) : QWidget(parent) {
        CefWindowInfo window_info;
#if defined(Q_OS_WIN)
        window_info.SetAsChild((HWND)winId(), {0, 0, width(), height()});
#endif
        CefBrowserSettings browser_settings;

        CefBrowserHost::CreateBrowser(window_info, this,
            "file:///index.html", browser_settings, nullptr, nullptr);
    }

    CefRefPtr<CefLifeSpanHandler> GetLifeSpanHandler() override {
        return this;
    }

    void OnAfterCreated(CefRefPtr<CefBrowser> browser) override {
        CEF_REQUIRE_UI_THREAD();
        this->browser = browser;
    }

    // C++ 调用 JS
    void callJs(const std::string& msg) {
        if (browser) {
            CefRefPtr<CefFrame> frame = browser->GetMainFrame();
            std::string jsCode = "onCppMessage('" + msg + "')";
            frame->ExecuteJavaScript(jsCode, frame->GetURL(), 0);
        }
    }

private:
    CefRefPtr<CefBrowser> browser;
    IMPLEMENT_REFCOUNTING(CefBrowserWidget);
};

4. index.html (放在可访问路径下)

复制代码
复制代码
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Qt + CEF Demo</title>
  <script>
    // JS -> C++
    function sendToCpp() {
        let msg = document.getElementById("msg").value;
        let result = callCpp(msg);  // 调用绑定的 C++ 函数
        alert("C++ 返回: " + result);
    }

    // C++ -> JS
    function onCppMessage(text) {
        alert("来自 C++ 的消息: " + text);
    }
  </script>
</head>
<body>
  <h2>Qt + CEF + JS 交互 Demo</h2>
  <input type="text" id="msg" value="你好 C++">
  <button onclick="sendToCpp()">发送给 C++</button>
</body>
</html>

效果:

  1. 在 Qt 窗口中打开 index.html

  2. 输入内容并点击按钮,JS 调用 callCpp(),C++ 收到参数并返回字符串。

  3. C++ 可以调用 callJs("Hello from C++"),触发 JS 函数 onCppMessage()

相关推荐
zmzb010318 小时前
C++课后习题训练记录Day53
数据结构·c++·算法
charlie11451419118 小时前
如何把 Win32 窗口“置顶”(Windows + C++)
开发语言·c++·windows·笔记·学习·软件工程
妮妮喔妮18 小时前
Nextjs的SSR服务器端渲染为什么优化了首屏加载速度?
开发语言·前端·javascript
咔咔咔的18 小时前
2110. 股票平滑下跌阶段的数目
c++
SmoothSailingT18 小时前
C/C++与C#——指针的作用
开发语言·c++·c
天赐学c语言19 小时前
12.18 - 有效的括号 && C语言中static的作用
数据结构·c++·算法·leecode
Gazer_S19 小时前
【Vue Router 路由守卫(Navigation Guards)指南:概念、执行顺序、beforeResolve、异步路由组件】
前端·javascript·vue.js
半梅芒果干19 小时前
vue3 新建文件store自动导入
开发语言·前端·javascript
玖笙&19 小时前
✨万字解析解析:Vue.js优雅封装级联选择器组件(附源码)
前端·javascript·vue.js·前端框架
烟袅19 小时前
深入理解 React 中 useState 与 useEffect
前端·javascript·react.js