Details
-
Bug
-
Resolution: Unresolved
-
P2: Important
-
None
-
6.2.0
-
None
Description
There is an inconsistency in QWebChannel for interfacing between Javascript and Qt types. In short:
- I can use a USVString ( https://developer.mozilla.org/en-US/docs/Web/API/Blob/text ) as a QString argument in a Q_INVOKABLE function
- I can NOT use an ArrayBuffer ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer ) as a QByteArray argument in a Q_INVOKABLE function
This seems to be due to a lack of programming, as this error is produced:
Could not convert argument QJsonValue(object, QJsonObject()) to target type QByteArray .
I have filed this bug report so that this behaviour is fixed. For the mean time, I am going to have to find a workaround, because I am unable to figure out how to transfer an ArrayBuffer through QWebChannel into c++. I have tried using QVariant and QJsonValue, with no luck.
To demonstrate and reproduce what I am trying to do, first create this basic class that will expose Q_INVOKABLE functions in javascript:
#ifndef QWEBCHANNELOBJECT_H #define QWEBCHANNELOBJECT_H #include <QObject> class QWebChannelObject : public QObject { Q_OBJECT public: explicit QWebChannelObject( QObject *parent = nullptr ) : QObject(parent) {} QByteArray byteArray() const { return m_ByteArray; } QString string () const { return m_String ; } Q_INVOKABLE void setByteArray( QByteArray byteArray ) { m_ByteArray = byteArray; emit byteArrayChanged(); }; Q_INVOKABLE void setString ( QString string ) { m_String = string ; emit stringChanged (); }; signals: void byteArrayChanged(); void stringChanged (); private: QByteArray m_ByteArray; QString m_String ; }; #endif // QWEBCHANNELOBJECT_H
Next, the following block of code can be inserted into main():
/* Load Url */ QWebEngineView wev; QUrl url( "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png" ); { QEventLoop waitForLoad; QObject::connect ( wev.page(), &QWebEnginePage::loadFinished, &waitForLoad, &QEventLoop::quit ); wev.load(url); waitForLoad.exec(); QObject::disconnect( wev.page(), &QWebEnginePage::loadFinished, &waitForLoad, &QEventLoop::quit ); } /* Setup Web Channel */ QWebChannel wc; QWebChannelObject wco; { QFile f_QWebChannel( ":/qtwebchannel/qwebchannel.js" ); f_QWebChannel.open( QIODevice::ReadOnly ); QString j_QWebChannel = f_QWebChannel.readAll(); wco.setObjectName( "wco" ); wc.registerObject( wco.objectName(), &wco ); wev.page()->setWebChannel(&wc); wev.page()->runJavaScript( j_QWebChannel ); } /* Try and set ByteArray and QString */ QEventLoop waitForByteArray; { QObject::connect( &wco, &QWebChannelObject::byteArrayChanged, &waitForByteArray, &QEventLoop::quit ); wev.showNormal(); wev.page()->runJavaScript( QString(R"( window.webChannel = new QWebChannel( qt.webChannelTransport, function( channel ){ var %1 = channel.objects.%2; fetch( "%3" ) .then( res => res.blob() ) .then( async(blob) => { const byteArray = await blob.arrayBuffer(); const string = await blob.text(); %1.setString ( string ); // Works %1.setByteArray( byteArray ); // Produces error }); }); )") .arg( wco.objectName() ) .arg( wc.registeredObjects().key(&wco) ) .arg( url.toString() ) ); waitForByteArray.exec(); QObject::disconnect( &wco, &QWebChannelObject::byteArrayChanged, &waitForByteArray, &QEventLoop::quit ); } QString s = wco.string (); QByteArray ba = wco.byteArray(); qDebug() << s.size() << ba.size();
Running the above code will produce the following error:
Could not convert argument QJsonValue(object, QJsonObject()) to target type QByteArray .
However, if this line is removed from the javascript:
%1.setByteArray( byteArray ); // Produces error
It works fine, meaning that I can transfer string data through QWebChannel, but not a byte array.