美文网首页
Qt for Android中调用百度地图

Qt for Android中调用百度地图

作者: Qt工坊 | 来源:发表于2019-03-21 14:14 被阅读0次

    首先感谢参考链接中的博主wkcagd,在他文章里面,基于websocket介绍了利用Qt官方js脚本qwebchannel.js文件,实现C++同js的互相通信方法。
    关于在Qt中调用百度地图,网上能找到在桌面版中的实现方法,也是通过qwebchannel.js实现的;但在Android手机上实现Qt同百度地图的交互,完全套用桌面开发的方法行不通,还需要实现一些附加的工作,比如:需要自己手动创建websocket来实现C++代码同js之间的通信。

    四个重要的类

    • QWebSocketServer
    • WebSocketTransport
      继承于QWebChannelAbstractTransport
    • WebSocketChannel
      继承于QWebChannel
    • WebChannelBridge
      继承于QObject,作用如下:
      1. 从C++发送信号并传递参数到js;
      2. 从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

    参考链接

    https://www.cnblogs.com/wkcagd/p/7732330.html

    相关文章

      网友评论

          本文标题:Qt for Android中调用百度地图

          本文链接:https://www.haomeiwen.com/subject/ebjzpqtx.html