首先感谢参考链接中的博主wkcagd,在他文章里面,基于websocket介绍了利用Qt官方js脚本qwebchannel.js文件,实现C++同js的互相通信方法。
关于在Qt中调用百度地图,网上能找到在桌面版中的实现方法,也是通过qwebchannel.js实现的;但在Android手机上实现Qt同百度地图的交互,完全套用桌面开发的方法行不通,还需要实现一些附加的工作,比如:需要自己手动创建websocket来实现C++代码同js之间的通信。
四个重要的类
- QWebSocketServer
- WebSocketTransport
继承于QWebChannelAbstractTransport - WebSocketChannel
继承于QWebChannel - WebChannelBridge
继承于QObject,作用如下:- 从C++发送信号并传递参数到js;
- 从js调用C++的槽函数。
WebSocketTransport类的实现
继承QWebChannelAbstractTransport,实现WebSocketTransport类
websockettransport.h
#ifndef WEBSOCKETTRANSPORT_H
#define WEBSOCKETTRANSPORT_H
#include <QWebChannelAbstractTransport>
QT_BEGIN_NAMESPACE
class QWebSocket;
QT_END_NAMESPACE
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;
};
#endif // WEBSOCKETTRANSPORT_H
websocketchannel.cpp
#include "websocketchannel.h"
#include <QWebSocketServer>
#include "websockettransport.h"
WebSocketChannel::WebSocketChannel(QWebSocketServer *server)
:_server(server)
{
connect(server, &QWebSocketServer::newConnection,
this, &WebSocketChannel::handleNewConnection);
connect(this, &WebSocketChannel::clientConnected,
this, &WebSocketChannel::connectTo);
}
void WebSocketChannel::handleNewConnection()
{
emit clientConnected(new WebSocketTransport(_server->nextPendingConnection()));
}
WebSocketChannel类的实现
继承QWebChannel,实现WebSocketChannel类
websocketchannel.h
#ifndef WEBSOCKETCHANNEL_H
#define WEBSOCKETCHANNEL_H
#include <QWebChannel>
class QWebSocketServer;
class WebSocketTransport;
class WebSocketChannel : public QWebChannel
{
Q_OBJECT
public:
WebSocketChannel(QWebSocketServer *server);
signals:
void clientConnected(WebSocketTransport *client);
private slots:
void handleNewConnection();
private:
QWebSocketServer *_server;
};
#endif // WEBSOCKETCHANNEL_H
websocketchannel.cpp
#include "websockettransport.h"
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QWebChannelAbstractTransport>
#include <QWebSocket>
/*!
Construct the transport object and wrap the given socket.
The socket is also set as the parent of the transport object.
*/
WebSocketTransport::WebSocketTransport(QWebSocket *socket)
: QWebChannelAbstractTransport(socket)
, m_socket(socket)
{
connect(socket, &QWebSocket::textMessageReceived,
this, &WebSocketTransport::textMessageReceived);
connect(socket, &QWebSocket::disconnected,
this, &WebSocketTransport::deleteLater);
}
/*!
Destroys the WebSocketTransport.
*/
WebSocketTransport::~WebSocketTransport()
{
m_socket->deleteLater();
}
/*!
Serialize the JSON message and send it as a text message via the WebSocket to the client.
*/
void WebSocketTransport::sendMessage(const QJsonObject &message)
{
QJsonDocument doc(message);
m_socket->sendTextMessage(QString::fromUtf8(doc.toJson(QJsonDocument::Compact)));
}
/*!
Deserialize the stringified JSON messageData and emit messageReceived.
*/
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);
}
WebChannelBridge类的实现
webchannelbridge.h
#ifndef WEBCHANNELBRIDGE_H
#define WEBCHANNELBRIDGE_H
#include <QObject>
class WebChannelBridge : public QObject
{
Q_OBJECT
public:
explicit WebChannelBridge(QObject *parent = nullptr);
signals:
//发送信号传递参数到js
void sendDataToJs(const QString& key, const QString& dataString);
public slots:
//从js调用槽函数设置数据到C++
void setDataToCPP(const QString& key, const QString& dataString);
};
#endif // WEBCHANNELBRIDGE_H
Qt for Android工程main.cpp主要代码
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
//启动web socket server监听端口12345,以实现C++同html的数据传输
QWebSocketServer server(QStringLiteral("QWebChannel Standalone Example Server"),
QWebSocketServer::NonSecureMode);
if (!server.listen(QHostAddress::LocalHost, 12345))
{
exit(-1);
}
QQmlApplicationEngine engine;
Engine *appEngine = Engine::getInstance();//这是笔者自己写的C++类,用于在QML中实现同C++的通信之用,和本文主要内容无关
appEngine->uiInit();
appEngine->basicInit();
//建立websocketchannl,该channel就可以用来同html通信了
WebSocketChannel channel(&server);
WebChannelBridge *bridge = new WebChannelBridge;
//注册C++对象,该类要继承自QObject
//将bridge对象注册到channel中,以便在html/js中调用
channel.registerObject(QStringLiteral("bridge"), (QObject*)bridge);
appEngine->setHttpBridge(bridge);
engine.rootContext()->setContextProperty("bridgeHtml",bridge);//注册对象bridge,在qml中调用
engine.rootContext()->setContextProperty("appEngine",appEngine);//注册对象appEngine,在qml中调用
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
exit(-1);
return app.exec();
}
html文件中主要代码实现
qwebchannel.js文件可以通过下方链接进行下载;请读者自行从其它地方下载jquery.min.js文件,放到该html文件同级的js目录中。请读者在该html文件中填入自己的百度开发者key。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/qwebchannel.js" ></script>
<style type="text/css">
body,html,#allmap {width: 100%;height: 100%;overflow: hidden;}
.userInfo {
position: fixed;
z-index: 100;
top: 10pt;
left: 10pt;}
.notes {
position: fixed;
z-index: 100;
top: 10pt;
right: 10pt;}
</style>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=请在这里填入读者自己的百度地图开发者key"></script>
<title>百度地图</title>
</head>
</body>
<body>
<div id="allmap"></div>
</html>
<script type="text/javascript">
// 百度地图API功能
var map = new BMap.Map("allmap");
var m_city = "北京";
map.centerAndZoom(m_city, 13); // 初始化地图,设置中心点坐标和地图级别
map.addControl(new BMap.OverviewMapControl()); //添加缩略地图控件
map.enableScrollWheelZoom(); //启用滚轮放大缩小
window.onload = function() {
var baseUrl = "ws://localhost:12345";
console.log("Connecting to WebSocket server at " + baseUrl + ".");
var socket = new WebSocket(baseUrl);
socket.onclose = function() {
console.error("web channel closed");
};
socket.onerror = function(error) {
console.error("web channel error: " + error);
};
socket.onopen = function() {
console.log("WebSocket connected, setting up QWebChannel.");
new QWebChannel(socket, function(channel) {
// make bridge object accessible globally
window.bridge = channel.objects.bridge;
window.bridge.sendDataToJs.connect(function(key,dataString){
//在这里处理从C++发送到js的信号
//在这里也可以调用C++的槽函数,如下:
window.bridge.setDataToCPP("Key_Data1","Some data string");
});
});
}
}
</script>
QML文件中百度地图的调用
将百度地图html文件和相关js文件放到Qt for Android工程目录的android/assets目录中,文件将被打包至apk安装包中。
WebView{//百度地图
id:webView
x:0
width: parent.width
height: parent.height
url:"file:///android_asset/baiduMap_online/index.html"
onLoadProgressChanged: {
if(webView.loadProgress == 100){
}
}
}
qwebchannel.js文件下载地址
链接:https://pan.baidu.com/s/1QMRuVwn-88IZX2N3QAggaw
提取码:j6y6
网友评论