Qt QWebSocket实现JS调用C++

这篇具有很好参考价值的文章主要介绍了Qt QWebSocket实现JS调用C++。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

本篇主要介绍实现JS调用C++的另一种方式,即QWebSocket+QWebChannel。与之前的一篇文章QWebEngine 加载网页及交互,实现C++与JS 相互调用中提到的仅通过QWebChannel 实现JS调C++相比,本文介绍的这种方式,更灵活,能实现更加复杂的业务功能。

1、QWebChannel如何与网页通信

这篇文章中提到的QWebChannel实现JS调用C++,有两个重要的步骤:

  1. 在前端代码中引入qwebchannel.js,并创建QWebChannel对象。
  2. 在C++代码中创建QWebChannel实例并注册JS端访问的C++对象,然后将其设置到QWebEnginePage中 ui->webview->page()->setWebChannel(pWebChannel);

为什么要这么做呢?根据Qt官方文档可知,要通过 QWebChannel 进行C++与JS 通信,前端必须使用 qwebchannel.js 提供的 JavaScript API。对于在 Qt WebEngine 中运行的前端页面,可以通过 qrc:///qtwebchannel/qwebchannel.js 加载该文件。对于外部浏览器页面,需要将该文件复制到 Web 服务器上。然后,实例化一个 QWebChannel 对象,并传递一个传输对象和一个回调函数给它。该回调函数将在QWebChannel初始化完成并发布的对象可用时被调用。代码如下:

new QWebChannel(qt.webChannelTransport, function(channel) {
	//在此处获取C++中注册到QWebChannel的对象
})

qt.webChannelTransport 是 QtWebEngine 挂载到前端全局环境中的 window.qt.webChannelTransport,即传输对象。传输对象实现了一个最小的消息传递接口。它有 send() 函数,该函数接受一个序列化的 JSON 消息并将其传输给服务器端的 QWebChannelAbstractTransport 对象。此外,当接收到来自服务器的消息时,应调用其 onmessage 属性。这部分代码在qwebchannel.js文件中,如下所示:


var QWebChannel = function(transport, initCallback)
{
    if (typeof transport !== "object" || typeof transport.send !== "function") {
        console.error("The QWebChannel expects a transport object with a send function and onmessage callback property." +
                      " Given is: transport: " + typeof(transport) + ", transport.send: " + typeof(transport.send));
        return;
    }

    var channel = this;
    this.transport = transport;
	
	//JS端向C++端发送消息
    this.send = function(data)
    {
        if (typeof(data) !== "string") {
            data = JSON.stringify(data);
        }
        channel.transport.send(data);
    }

	//接收C++端传来的消息
    this.transport.onmessage = function(message)
    {
        var data = message.data;
        if (typeof data === "string") {
            data = JSON.parse(data);
        }
        switch (data.type) {
            case QWebChannelMessageTypes.signal:
                channel.handleSignal(data);
                break;
            case QWebChannelMessageTypes.response:
                channel.handleResponse(data);
                break;
            case QWebChannelMessageTypes.propertyUpdate:
                channel.handlePropertyUpdate(data);
                break;
            default:
                console.error("invalid message received:", message.data);
                break;
        }
    }
};

那qt.webChannelTransport何时挂载的呢?就是在C++端调用page()->setWebChannel(pWebChannel)时将qt.webChannelTransport挂载到JS环境中,这一点可以通过注销这行代码运行程序看效果。你会看到终端报一个 js: Uncaught ReferenceError: qt is not defined的错误。所以要在网页加载完成之前调用setWebChannel函数。通过下图能更清楚的了解这个交互过程
qwebchannel.js,C++,QtWeb混合开发技术,javascript,c++,开发语言,qt,web,websocket

2、QWebSocket+QWebChannel与网页通信

2.1 WebSocketTransport

先看代码,WebSocketTransport类继承自QWebChannelAbstractTransport,用于发送和接收消息。它通过 textMessageReceived 处理所有QWebSocket接收的消息。同样,所有 sendTextMessage 的调用将通过 QWebSocket 发送给远程客户端。类声明如下

class QWebSocket;
class WebSocketTransport : public QWebChannelAbstractTransport
{
    Q_OBJECT
public:
    explicit WebSocketTransport(QWebSocket *socket);
    virtual ~WebSocketTransport();

    void sendMessage(const QJsonObject &message) override;

private slots:
    void textMessageReceived(const QString &message);

private:
    QWebSocket *m_socket;
};

源码如下:

#include "websockettransport.h"

#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QWebSocket>

WebSocketTransport::WebSocketTransport(QWebSocket *socket)
: QWebChannelAbstractTransport(socket)
, m_socket(socket)
{
    connect(socket, &QWebSocket::textMessageReceived,
            this, &WebSocketTransport::textMessageReceived);
    connect(socket, &QWebSocket::disconnected,
            this, &WebSocketTransport::deleteLater);
}

void WebSocketTransport::sendMessage(const QJsonObject &message)
{
    QJsonDocument doc(message);
    m_socket->sendTextMessage(QString::fromUtf8(doc.toJson(QJsonDocument::Compact)));
}

void WebSocketTransport::textMessageReceived(const QString &messageData)
{
    QJsonParseError error;
    QJsonDocument message = QJsonDocument::fromJson(messageData.toUtf8(), &error);
    if (error.error) {
        qWarning() << "Failed to parse text message as JSON object:" << messageData
                   << "Error is:" << error.errorString();
        return;
    } else if (!message.isObject()) {
        qWarning() << "Received JSON message that is not an object: " << messageData;
        return;
    }
    emit messageReceived(message.object(), this);
}

2.2 WebSocketClientWrapper

WebSocketClientWrapper 是连接到WebSocket服务的客户端的简单封装,将连接的socket 通过clientConnected信号传给消费者。


class WebSocketTransport;
class QWebSocketServer;
class WebSocketClientWrapper : public QObject
{
    Q_OBJECT

public:
    WebSocketClientWrapper(QWebSocketServer *server, QObject *parent = nullptr);

signals:
    void clientConnected(WebSocketTransport *client);

private slots:
    void handleNewConnection();

private:
    QWebSocketServer *m_server;
};

源码如下:

#include "websocketclientwrapper.h"
#include "websockettransport.h"
#include <QWebSocketServer>

WebSocketClientWrapper::WebSocketClientWrapper(QWebSocketServer *server, QObject *parent)
    : QObject(parent)
    , m_server(server)
{
    connect(server, &QWebSocketServer::newConnection,
            this, &WebSocketClientWrapper::handleNewConnection);
}

void WebSocketClientWrapper::handleNewConnection()
{
    emit clientConnected(new WebSocketTransport(m_server->nextPendingConnection()));
}

2.3 初始化WebSocket服务器

初始化WebSocket服务器,并连接到QWebChannel

    m_webSocketServer  = new QWebSocketServer(QStringLiteral("QWebSocketServer + QWebChannel Test"), QWebSocketServer::NonSecureMode);
    if (!m_webSocketServer->listen(QHostAddress::LocalHost, 65535)) {
        qFatal("Failed to open web socket server.");
        return 1;
    }
	
    m_webSocketClientWrapper = new WebSocketClientWrapper(m_webSocketServer);
    m_pWebObj =  new WebObject();
    QWebChannel *pWebChannel = new QWebChannel();
    pWebChannel->registerObject("nativeObj", m_pWebObj);
    //连接到webchannel
    connect(m_webSocketClientWrapper, &WebSocketClientWrapper::clientConnected,
                     &pWebChannel, &QWebChannel::connectTo);

2.4 前端网页代码修改

前端网页代码如下:

<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
		<meta name="viewport" content="width=device-width, viewport-fit=cover">
		<title>QWebEngineTest</title>
		
		<script type="text/javascript" src="./qwebchannel.js"></script>
		<script type="text/javascript">
			
			//C++ 调用showalert函数
			function showalert(text) 
			{
				alert(text)
			}	

			//C++ 调用getJsData函数
			function getJsData() 
			{
				return "C++ Call JS demo"
			}	

			var nativeObj 
			window.onload = function() {
				//创建websocket客户端
                var socket = new WebSocket('ws://127.0.0.1:65535');

                socket.onclose = function() {
                    console.error("web channel closed");
                };

                socket.onerror = function(error) {
                    console.error("web channel error: " + error);
                };

                socket.onopen = function() {
                    new QWebChannel(socket, function(channel) {
                        nativeObj = channel.objects.nativeObj;
                    	nativeObj.nativeTextChanged.connect(function(text)
						{
							alert("nativeTextChanged: " + text)
						})
                    });
                }
			}

			function jsCallCpp ()
			{
				nativeObj.setNativeText("JS Call C++ test ")
			}

			function getNativeText()
			{
				alert("new nativeText is: "  + nativeObj.nativeText)
			}
			
		</script>
	</head>
	<body>
		<p>
			QWebEngineTest
		</p>
		<button onclick="jsCallCpp()" >调用C++对象的函数setNativeText</button>
		<button onclick="getNativeText()" >获取C++对象属性nativeText </button>
	</body>
</html>

运行效果如下图所示
qwebchannel.js,C++,QtWeb混合开发技术,javascript,c++,开发语言,qt,web,websocket

至此我们实现了QWebSocket+QWebChannel与网页通信的功能,与单纯使用QWebChannel实现网页通信相比,QWebSocket+QWebChannel方式允许前端代码在任何浏览器上运行,而单纯使用QWebChannel的方式只能将前端网页嵌入到QWebEngine中展现。除此之外,前端代码中,QWebChannel 对象的创建时机也不同,QWebSocket+QWebChannel方式要求在onopen回调中创建QWebChannel对象,而只使用QWebChannel的方式在C++端调用该接口setWebChannel(pWebChannel)后就可以。

var socket = new WebSocket('ws://127.0.0.1:65535');
socket.onclose = function() {
	console.error("web channel closed");
};

socket.onerror = function(error) {
	console.error("web channel error: " + error);
};

socket.onopen = function() {
	//在onOpen函数中创建QWebChannel
	new QWebChannel(socket, function(channel) {
		nativeObj = channel.objects.nativeObj;
		nativeObj.nativeTextChanged.connect(function(text)
		{
			alert("nativeTextChanged: " + text)
		})
	});
}

总结

以上就是本文要讲的内容了,本文详细介绍了QWebChannel与网页端通信的两种方式,希望通过阅读本文,能帮你快速掌握在Qt 前后端混合开发模式下C++与JS通信的方法。对文中内容有任何疑问,都可以留言讨论!文章来源地址https://www.toymoban.com/news/detail-792612.html

到了这里,关于Qt QWebSocket实现JS调用C++的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • QWebEngine应用---基于QWebChannel实现网页与qt层交互

    Qt提供了QWebChannel实现和网页的通信,我们直接拿github上一个能直接运行的demo来做说明,demo是基于Widget,且页面是自己实现的页面,接着会介绍基于QML实现且页面是第三方网站如何使用的。 我们先看看demo的运行效果  左边是widget界面,右边是QWebEngineView,两边支持互发消息。

    2024年02月14日
    浏览(35)
  • Qt之qml和widget混合编程调用

    首先是创建一个widget项目 然后需要添加qml和quick的插件使用 QT += quickwidgets qml 接着要在界面上创建一个quickwidget和按钮 创建一个c++对象类 QObjectQml cpp实现文件 注册c++对象到系统中 接着c++的界面对象中调用即可 qml文件的实现如下: 运行结果如下:

    2024年02月14日
    浏览(36)
  • JS | JS调用EXE

    网上洋洋洒洒一大堆文章提供,然我还是没找打合适的方案: 注册表方案做了如下测试(可行但是不推荐?): 先,键入文件名为  myprotocal.reg  的注册表,并键入一下信息:

    2024年01月16日
    浏览(83)
  • Vue.js uni-app 混合模式原生App webview与H5的交互

    在现代移动应用开发中,原生App与H5页面之间的交互已经成为一个常见的需求。本文将介绍如何在Vue.js框架中实现原生App与H5页面之间的数据传递和方法调用。我们将通过一个简单的示例来展示如何实现这一功能。 效果图如下: 首先,我们需要在Vue.js项目中引入原生App与H5页面

    2024年02月16日
    浏览(69)
  • C++ 调用js 脚本

    需求: 使用Qt/C++ 调用js 脚本。Qt 调用lua 脚本性能应该是最快的,但是需要引入第三方库,虽然也不是特别麻烦,但是调用js脚本,确实内置的功能(C++ 调用lua 脚本-CSDN博客) 步骤: 1,pro 引入   2,调用js 脚本 3,js 脚本编写 4,效果 js 和lua对比:  目前Qt使用现成的js生态

    2024年02月22日
    浏览(35)
  • js调用栈分析

    s调用栈 执行上下文:执行上下文就是当前js代码被解析和执行所在环境的抽象的概念(执行环境) js中的任何代码都是在执行上下文中执行的 js的执行环境:JS代码运行起来,执行上下文 js的执行上下文分为三种: 全局上下文:默认的他是最基础的执行上下文 创建全局对象

    2024年02月14日
    浏览(28)
  • js调用android 方法

    客户端

    2024年02月07日
    浏览(30)
  • JCEF中js与java交互、js与java相互调用

    jcef中js与java相互调用,java与js相互调用,chrome与java相互调用,java与chrome相互调用、jcef与java相互调用 前提:https://blog.csdn.net/weixin_44480167/article/details/133170970(java内嵌浏览器CEF-JAVA、jcef、java chrome) 转自:https://lingkang.top/archives/jcef-zhong-js-yu-java-jiao-hu 代码如下 src/main/resourc

    2024年02月06日
    浏览(36)
  • js调用本地exe程序

    通过添加注册表来实现调用 新建reg文件 内容如下 双击reg文件执行 系统提示以上信息就说明注册表添加成功 页面调用 就可以啦!!!

    2024年02月11日
    浏览(25)
  • js封装SDK 在VUE、小程序、公众号直接调用js调用后端接口(本文以vue项目为例)

    1.封装一个js文件 msgSdk.js 注意:需要修改这个请求地址  apiServiceAddress 2.在index.html中引入 msgSdk.js文件 和 jquery文件 3.在页面中调用

    2024年04月27日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包