QT C++ QWebEngine与Web JS之间通信

Qt 与 Web 通信指南(QWebEngineView + QWebChannel)

概览

  • 目标:让网页 JavaScript 与 Qt 客户端进行双向通信(调用本地方法、通知 UI)。
  • 技术栈:Qt WebEngineWidgets + Qt WebChannel + JavaScript qwebchannel.js
  • 适用场景:在 QWebEngineView 内嵌外部或内部网页,并需要与桌面端交互。

通信模型

  • Qt 暴露一个 QObject(如 WebBridge),注册到 QWebChannel
  • Web 端通过 qwebchannel.js 获得该对象(例如 bridge),直接调用其 slot 方法。
  • Qt 端通过 signals 向 UI 或其他模块转发事件,或主动调用 evaluateJavaScript 与 Web 交互。

快速集成步骤

  1. 引入依赖并链接:

    • CMake:

      cmake 复制代码
      find_package(Qt6 REQUIRED COMPONENTS WebEngineWidgets WebChannel)
      target_link_libraries(QuantClient PRIVATE Qt6::WebEngineWidgets Qt6::WebChannel)
  2. 实现桥对象(Qt → Web 暴露):

    • src/gui/web/WebBridge.h / src/gui/web/WebBridge.cpp
    • 暴露 slot,在需要处 emit 信号给 UI 层。
  3. QWebEngineView 完成加载前注册通道:

    • webView->page()->setWebChannel(channel);
  4. Web 端加载 qwebchannel.js 并初始化通道,获取 bridge 对象进行调用。

Qt 侧代码示例

cpp 复制代码
// StrategyPerformanceDialog.cpp(片段)
QWebChannel* channel = new QWebChannel(this);
WebBridge* bridge = new WebBridge(this);
channel->registerObject(QStringLiteral("bridge"), bridge);
webView->page()->setWebChannel(channel);
QObject::connect(bridge, &WebBridge::openStrategyDetailRequested, this, &StrategyPerformanceDialog::onStrategyDetailRequested);
cpp 复制代码
// WebBridge.h(片段)
class WebBridge : public QObject {
    Q_OBJECT
public:
    explicit WebBridge(QObject *parent = nullptr);
public slots:
    void refreshStrategyData();
    void openStrategyDetail(const QString &strategyId);
signals:
    void openStrategyDetailRequested(const QString &strategyId);
};
cpp 复制代码
// WebBridge.cpp(片段)
void WebBridge::openStrategyDetail(const QString &strategyId) {
    emit openStrategyDetailRequested(strategyId);
}

Web 侧代码示例

页面可改(直接在 HTML 中)

html 复制代码
<script src="qrc:///qtwebchannel/qwebchannel.js"></script>
<script>
  new QWebChannel(qt.webChannelTransport, function(channel) {
    const bridge = channel.objects.bridge;
    bridge.refreshStrategyData();
    bridge.openStrategyDetail("strategy_123");
  });
</script>

页面不可改(Qt 侧注入)

cpp 复制代码
// 加载完成后动态注入脚本
connect(webView, &QWebEngineView::loadFinished, this, [webView](bool){
    webView->page()->runJavaScript(R"((function(){
      var s=document.createElement('script');
      s.src='qrc:///qtwebchannel/qwebchannel.js';
      s.onload=function(){
        new QWebChannel(qt.webChannelTransport,function(c){
          window.bridge=c.objects.bridge;
        });
      };
      document.head.appendChild(s);
    })();)"
    );
});

预注入(更稳,文档创建阶段)

cpp 复制代码
QWebEngineScript script;
script.setName(QStringLiteral("qwebchannel-loader"));
script.setInjectionPoint(QWebEngineScript::DocumentCreation);
script.setWorldId(QWebEngineScript::MainWorld);
script.setRunsOnSubFrames(true);
script.setSourceCode(QStringLiteral(
  "(function(){var s=document.createElement('script');" 
  "s.src='qrc:///qtwebchannel/qwebchannel.js';" 
  "s.onload=function(){new QWebChannel(qt.webChannelTransport,function(c){window.bridge=c.objects.bridge;});};" 
  "document.head.appendChild(s);})();"
));
webView->page()->scripts().insert(script);

常见问题与排错

  • 链接错误:Undefined symbols for architecture arm64 → 未将 WebBridge.cpp 加入构建或未链接 Qt6::WebChannel
  • 头文件找不到:'config/AppConfig.h' file not found#include 相对路径错误,从 src/gui/mainwindowsrc/gui/config 需用 ../config/AppConfig.h
  • qwebchannel.js 加载失败:确保使用 qrc:///qtwebchannel/qwebchannel.js,并已链接 Qt6::WebChannel
  • JS 不生效:确认已调用 webView->page()->setWebChannel(channel),且对象名与 JS 一致(如 bridge)。

安全与最佳实践

  • 只暴露必要的 slot,在 Qt 侧校验参数与权限。
  • 对外部页面建议使用注入方式并限制可用接口。
  • 使用明确的对象名与命名空间,避免冲突。

扩展能力

  • Qt → Web 主动调用:webView->page()->runJavaScript("doSomething()")
  • Web → Qt 回调返回值:QWebEnginePage::runJavaScript 支持回调函数拿到执行结果。
相关推荐
kirinlau5 小时前
pinia状态管理在vue3项目中的用法详解
前端·javascript·vue.js
zhuà!5 小时前
腾讯地图TMap标记反显,新增标记
前端·javascript·vue.js
未知原色5 小时前
web worker使用总结(包含多个worker)
前端·javascript·react.js·架构·node.js
牵牛老人6 小时前
【基于Qt6.5和H5做一个简单的物料管理ERP系统的架构设计】
qt
似水এ᭄往昔6 小时前
【C++】--封装红⿊树实现mymap和myset
开发语言·数据结构·c++·算法·stl
charlie1145141916 小时前
嵌入式现代C++教程:C++98——从C向C++的演化(3)
c语言·开发语言·c++·笔记·学习·嵌入式
moonquakeTT6 小时前
C++:深拷贝与浅拷贝
c++
程序员zgh6 小时前
C语言 指针用法与区别(指针常量、常量指针、指针函数、函数指针、二级指针)
c语言·开发语言·jvm·c++
冉佳驹6 小时前
C++ ——— 仿函数的使用、继承方式、赋值转换规则、菱形继承与虚继承
c++·继承·virtual·仿函数·菱形继承·模板特化·虚继承
inferno6 小时前
JavaScript 基础
开发语言·前端·javascript