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()

相关推荐
烛阴2 小时前
【TS 设计模式完全指南】TypeScript 装饰器模式的优雅之道
javascript·设计模式·typescript
半桔2 小时前
【STL源码剖析】二叉世界的平衡:从BST 到 AVL-tree 和 RB-tree 的插入逻辑
java·数据结构·c++·算法·set·map
aidingni8883 小时前
掌握 JavaScript 中的 Map 和 Set
前端·javascript
闲云野鹤_3 小时前
JavaScript学习笔记
javascript
努力往上爬de蜗牛3 小时前
react3面试题
javascript·react.js·面试
开心不就得了3 小时前
React 进阶
前端·javascript·react.js
jeff渣渣富3 小时前
Taro 2.x 分包优化实践:如何防止分包文件被打包到主包
前端·javascript
R_.L3 小时前
【项目】 :C++ - 仿mudou库one thread one loop式并发服务器实现(代码实现)
服务器·开发语言·c++
R_.L3 小时前
【项目】 :C++ - 仿mudou库one thread one loop式并发服务器实现(模块划分)
服务器·c++