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 支持回调函数拿到执行结果。
相关推荐
神仙别闹2 小时前
基于 C++ 实现两个有序链表序列的交集
java·c++·链表
mayaairi3 小时前
Vue2 生命周期完全指南:从创建到销毁的8个钩子函数
前端·javascript·vue.js
研☆香4 小时前
一个简单的气泡弹窗制作
javascript
hansang_IR4 小时前
【题解】[APIO2023] 赛博乐园 / cyberland
c++·算法·图论
大模型丫丫4 小时前
用 TypeScript、NestJS 和 LangGraph 搭建一个可控的 AI Agent
javascript·人工智能·typescript
IMPYLH4 小时前
HTML 的 <pre> 元素
前端·javascript·html
落羽的落羽5 小时前
【AI】快速理解AI应用的相关名词概念
linux·c++·人工智能·python·计算机网络·算法
刚入门的大一新生5 小时前
Linux-进程控制
linux·运维·服务器·c++
shmily麻瓜小菜鸡5 小时前
JavaScript / TypeScript 易踩坑知识点 —— 异步编程类
开发语言·javascript·typescript
刃神太酷啦5 小时前
Redis 进阶核心:持久化 (RDB/AOF)、事务与主从复制全解析----《Hello Redis!》(5)
linux·c语言·数据库·c++·redis·缓存·bootstrap