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 支持回调函数拿到执行结果。
相关推荐
QT 小鲜肉1 小时前
【QT/C++】Qt样式设置之CSS知识(系统性概括)
linux·开发语言·css·c++·笔记·qt
Main. 242 小时前
从0到1学习Qt -- 常见控件QWidget(二)
qt·学习
洛克希德马丁2 小时前
Qt配置安卓开发环境
android·开发语言·qt
我要升天!2 小时前
QT-- 理解项目文件
开发语言·数据库·qt
Elias不吃糖2 小时前
NebulaChat 框架学习笔记:深入理解 Reactor 与多线程同步机制
linux·c++·笔记·多线程
友善啊,朋友2 小时前
Qt:判断一个sql语句是否是select语句
sql·qt
转基因2 小时前
命名空间与匿名空间
c++
煤球王子2 小时前
学而时习之:C++中的动态内存管理
c++
dualven_in_csdn2 小时前
【electron】解决CS里的全屏问题
前端·javascript·electron