Qt5.9 WebChannel
Qt WebChannel enables peer-to-peer communication between a server (QML/C++ application) and a client (HTML/JavaScript or QML application). It is supported out of the box by Qt WebEngine. In addition it can work on all browsers that support WebSockets, enabling Qt WebChannel clients to run in any JavaScript environment (including QML). This requires the implementation of a custom transport based on Qt WebSockets.
The module provides a JavaScript library for seamless integration of C++ and QML applications with HTML/JavaScript and QML clients. The clients must use the JavaScript library to access the serialized QObjects published by the host applications.
QWebChannel Class
Exposes QObjects to remote HTML clients.
The QWebChannel fills the gap between C++ applications and HTML/JavaScript applications. By publishing a QObject derived object to a QWebChannel and using the qwebchannel.js on the HTML side, one can transparently access properties and public slots and methods of the QObject. No manual message passing and serialization of data is required, property updates and signal emission on the C++ side get automatically transmitted to the potentially remotely running HTML clients. On the client side, a JavaScript object will be created for any published C++ QObject. It mirrors the C++ object's API and thus is intuitively useable.
The C++ QWebChannel API makes it possible to talk to any HTML client, which could run on a local or even remote machine. The only limitation is that the HTML client supports the JavaScript features used by qwebchannel.js. As such, one can interact with basically any modern HTML browser or standalone JavaScript runtime, such as node.js.
Qt WebChannel JavaScript API
Setting up the JavaScript API
To communicate with a QWebChannel or WebChannel, a client must use and set up the JavaScript API provided by qwebchannel.js. For clients run inside Qt WebEngine, you can load the file via qrc:///qtwebchannel/qwebchannel.js. For external clients, you need to copy the file to your web server. Then instantiate a QWebChannel object and pass it a transport object and a callback function, which will be invoked once the initialization of the channel finishes and the published objects become available.
The transport object implements a minimal message passing interface. It should be an object with a send() function, which takes a stringified JSON message and transmits it to the server-side QWebChannelAbstractTransport object. Furthermore, its onmessage property should be called when a message from the server was received. Alternatively, you can use a WebSocket to implement the interface.
Note that the JavaScript QWebChannel object should be constructed once the transport object is fully operational. In case of a WebSocket, that means you should create the QWebChannel in the socket's onopen handler. Take a look at the Qt WebChannel Standalone Example to see how this is done.
Interacting with QObjects
Once the callback passed to the QWebChannel object is invoked, the channel has finished initialization and all published objects are accessible to the HTML client via the channel.objects property. Thus, assuming an object was published with the identifier "foo", then we can interact with it as shown in the example below. Note that all communication between the HTML client and the QML/C++ server is asynchronous. Properties are cached on the HTML side. Furthermore keep in mind that only QML/C++ data types which can be converted to JSON will be (de-)serialized properly and thus accessible to HTML clients.
new QWebChannel(yourTransport, function(channel) { // Connect to a signal: channel.objects.foo.mySignal.connect(function() { // This callback will be invoked whenever the signal is emitted on the C++/QML side. console.log(arguments); }); // To make the object known globally, assign it to the window object, i.e.: window.foo = channel.objects.foo; // Invoke a method: foo.myMethod(arg1, arg2, function(returnValue) { // This callback will be invoked when myMethod has a return value. Keep in mind that // the communication is asynchronous, hence the need for this callback. console.log(returnValue); }); // Read a property value, which is cached on the client side: console.log(foo.myProperty); // Writing a property will instantly update the client side cache. // The remote end will be notified about the change asynchronously foo.myProperty = "Hello World!"; // To get notified about remote property changes, // simply connect to the corresponding notify signal: foo.onMyPropertyChanged.connect(function(newValue) { console.log(newValue); }); // One can also access enums that are marked with Q_ENUM: console.log(foo.MyEnum.MyEnumerator); });