Hybrid applications, which mix a UI built with Qt Widgets or Qt Quick with embedded HTML websites, are very popular. In particular, something like an HTML 5 app framework is often requested by customers. Qt WebKit makes it trivial to embed HTML content in any graphical application. But how does one bridge the gap between C++/QML on one side, and HTML/JavaScript on the other side?
A bit of history
In the single-process world of the C++ Qt WebKit API, it was easily possible to publish a QObject instance to the JavaScript client side, thanks the Qt WebKit Bridge. This is a crucial functionality for any application that uses Qt WebKit as the foundation for an HTML app framework or similar.
Up until now though, WebView, the Qt Quick 2 integration of Qt WebKit, was missing this functionality. The reason for that was the multi-process architecture at the core of WebKit2, which is used internally by WebView; in such an environment, the synchronous API of the WebKit bridge cannot be supported, since inter-process communication is inherently asynchronous. Due to that, hybrid QML/HTML applications were notoriously hard to implement.
In October 2011, Noam Rosenthal presented an alternative approach to the problem, which he called Qt WebChannel. His idea was simple and powerful at the same time: By leveraging Qt's introspection system, he could create mock objects on the JavaScript client side which mirror the API of the server-side QML/QObject objects. For communication between the QML host and the HTML/JavaScript client, he chose WebSockets. But, contrary to the WebKit Bridge, the API provided by the WebChannel is completely asynchronous.
Despite the huge interest in hybrid QML/HTML applications, Nokia and nowadays, Digia, did not prioritize work on this missing functionality. Priorities lay elsewhere and the Qt WebChannel project never left the proof-of-concept stage on Qt Labs.
At the beginning of 2013, a customer approached KDAB and requested the development of a QML application with an HTML 5 application framework. Naturally, we chose Qt WebChannel as a foundation and started polishing it. In this first real-world use-case, numerous bugs and missing functionality were found, fixed and upstreamed to the Qt Labs repository. In the process, I essentially took up maintainership of the Qt WebChannel project. Eventually, the codebase worked reliably and efficiently even on embedded devices. Still, it remained a Qt Labs project and as such awkward to use by others.
Making it Official
Over the last couple of months, I had the pleasure to work on Qt WebChannel exclusively, sponsored by KDAB. The goal was to create a proper Qt module which can be used by hybrid QML/HTML applications. At this year's Qt Contributor Summit the design was reviewed and approved for inclusion in Qt 5.4. A few days ago now, Qt WebChannel was added as a new module for Qt 5.4. What is left now, is the inclusion of two already approved patches, which provide an easy-to-use integration of the Qt WebChannel functionality into Qt WebKit with a minimum of boiler-plate code.
A QML/HTML hybrid application in Qt 5.4
So, what is necessary to build a hybrid QML/HTML application in the upcoming Qt 5.4? The following shows how to use the new Qt WebChannel module.
QML Server Side
On the QML server side, first import the Qt WebChannel module, as well as the Qt WebKit module and its experimental one:
This single line is all you need to publish potentially multiple objects. Internally, this will use the WebKit IPC mechanism to transmit method calls, signals and property update notifications to the HTML clients. You can also create a WebChannel object externally and set it on multiple WebViews if necessary.
HTML/JavaScript client side
On the client side, a bit of boiler-plate code is still required. I tried to minimize it as much as possible, and plan to improve this situation even further in the future. First, include the client-side qwebchannel.js
library via its Qt resource URL:
34 Comments
19 - Aug - 2014
Roger
Is it possible to run a qml client app in web browser? And connect to the server side through websocket?
19 - Aug - 2014
Milian Wolff
Yes, that is theoretically possible. Take a look at QML-Web by my colleague Anton Kreuzkamp. There's also the talk about QML Web by him and Thomas McGuire from last years DevDays Europe. It should be fairly trivial to pair that with the Qt WebChannel to seamlessly write QML web applications with a C++ or QML server-side.
26 - Aug - 2014
rubizm
QmlWeb would be the perfect complement for Qt WebChannel!
As for the server/websocket connection, this is also a great solution for situations where the JS code would be just too much for the browser to parse. For example in a communication web client...
19 - Aug - 2014
Christian Feldbacher
Nice work Milian!
23 - Aug - 2014
David Smid
Is there a C++ variant of qwebchannel.js ? I mean can I use WebChannel with a web socket transport in a QML/C++ frontend to communicate with a remote QML/C++ backend as well as from HTML/JavaScript ?
24 - Aug - 2014
Milian Wolff
No, qwebchannel.js is only available as a JavaScript library. If you want to use it in C++, you'll need to do more to recreate the objects in a typesafe manner on the client side. Watch out for Qt Replicant, which was announced on the development mailing list of Qt and demoed at this years Qt Contributor Summit. We will definitely blog about it, once the code is made public.
That said, you can import qwebchannel.js in QML and use it to communicate with a C++ or QML backend. Take a look at the WebChannel tests which do something like that. For communication purposes, you'll need to create a WebSocket-based transport layer, which you can copy from the WebChannel examples (e.g. standalone).
Enjoy!
1 - Sept - 2014
QML
Great! So, we can make a middleware with QML&C++ now. Q2EE? :)
8 - Sept - 2014
Noam Rosenthal
Awesome work Milian! Glad to see this idea from 3 years ago survived somehow...
9 - Sept - 2014
Milian Wolff
Hey Noam,
I'm glad to see you are still around! Thanks a lot for spearheading this effort back then, your initial idea was spot on. Much appreciated!
22 - Nov - 2014
Eric
so.. what about using it with QtWebEngine ?
23 - Nov - 2014
Milian Wolff
It will be just as easy as Qt WebKit with Qt 5.5. In Qt 5.4, you'll have to do some manual work and use a WebSocket for communication. Or apply this locally: https://codereview.qt-project.org/#/c/93800/
27 - Jan - 2015
Glen
Hi Millian With my understanding, webchannel is working in asychnchronized way. in our case, there are a few number of custom properties and methods must be accessed synchronously. Any idea to use Webchannel in synchronized way?
BR Glen
27 - Jan - 2015
Milian Wolff
Hey Glen,
please read the article again. There is no way to make the API synchronous, as we must do inter-process communication, which is inherently asynchronous.
I suggest you refactor your code. There is normally always a way to do so, in order to work properly with asynchronous API.
Bye
13 - Mar - 2015
Nehal
Hi -- In 5.4 can you describe how the process might work with the QML WebSocket Server as the WebChannel transport (rather than the ipc approach which looks like it won't be available until 5.5)
The modification on the javascript client side seems simple enough (use a websocket with the QML servers url rather than the navigator.qtWebChannel)
but on the QML server side I'm a little uncertain... basically I know you need to create a webSocket server, and then create a WebChannel with the websocket server as the transport, but I haven't been able to find any concrete instructions on how this is done in QML (I think the only thing I found was on the c++ side)
Thanks for the cool article!
4 - Sept - 2015
corey
if maybe you could look into my question .plz . thx .
http://stackoverflow.com/questions/32396649/how-to-invoke-c-qt-function-from-javascript-in-qwebengine?answertab=votes#tab-top
4 - Sept - 2015
Milian Wolff
Done, use
qt.webChannelTransport.
in QtWebEngine.9 - Sept - 2015
Siamak Rahimi Motem
Tnx a million. For later readers, Note for using this we have to import import QtWebEngine 1.1
10 - Sept - 2015
Alexandre Cossette-Pacheco
I was looking for exactly the same information while porting from Qml1+WebView (1.0) + javascriptWindowObjects to Qml2+WebEngine+WebChannel.
Could not find it in the 5.5 documentation, so thanks a lot for this answer!
There really should be a full WebEngine+WebChannel Qml example in the docs, as it's the only real replacement for the full Qml1+WebView +javascriptWindowObjects integration.
9 - Sept - 2015
Siamak Rahimi Motem
Hi Milian, you have answered a question about QtWebEngine that "It will be just as easy as Qt WebKit with Qt 5.5. In Qt 5.4, you’ll have to do some manual work and use a WebSocket for communication. " Now in the 5.5 I still do not see a way. I use qt.webChannelTransport. in the HTML side. But how should I connect to that in the c++/qml side ? Is it by setting transports property of WebChannel qml object ? If so, what should it be ? Thanks
9 - Sept - 2015
Milian Wolff
On the C++ side you can access the channel via the page:
http://doc.qt.io/qt-5/qwebenginepage.html#webChannel
On the QML side the WebEngineView has a webChannel property, i.e.:
For some reason, the documentation of this property is missing, I'll investigate and improve that.
Cheers
9 - Sept - 2015
Milian Wolff
The documentation should get updated soon, the current snapshot includes the documentation properly:
http://doc-snapshots.qt.io/qt5-5.6/qml-qtwebengine-webengineview.html#webChannel-prop
6 - Nov - 2015
Jesus Sanchez
Hi, thank you so much for sharing all this information. I have a problem, using WebView like your example works perfect, recently I update Qt and I really like how WebEngineView works but I can't make that bridge between QML and HTML.
I'm using webChannel.registeredObjects:[myObject], like in your example but nothing seems to work. I don't know if I'm making things wrong. Thanks again, I hope you can help me.
6 - Nov - 2015
Jesus Sanchez
Never mind! I hadn't understood the question of corey.
qt.webChannelTransport
This do the trick, thank you so much, sorry that I didn't get it.
15 - Oct - 2015
Vyacheslav
Hello, what can I pass custom data into JS from C++ though QWebChannel?
16 - Oct - 2015
Milian Wolff
What problems exactly do you have? But I don't think the comment section of a blog post is the right place to get support. Please use the official Qt support channels for that, e.g. the mailing list.
3 - Nov - 2015
Ivan
Hi! I've seen the WebChannel examples(http://doc.qt.io/qt-5/qtwebchannel-examples.html) and would like to avoid WebSockets if possible. How to use QWebChannel without WebSockets correctly?
3 - Nov - 2015
Milian Wolff
Just use the webchannel that is bundled with QtWebKit's WebView or the analogous WebEngineView. See e.g.: http://doc-snapshots.qt.io/qt5-5.6/qml-qtwebengine-webengineview.html#webChannel-prop
17 - Nov - 2015
Ivan
thank you so much!
28 - Mar - 2017
Daniele
Hi Milian, I'm trying to use your example but I'm not able to get working. Is possible to have a repro working to look at?
29 - Mar - 2017
Milian Wolff
Hey Daniele,
what exactly is the problem? The Qt WebChannel repository contains examples in compilable form. Additionally, both Qt WebKit and WebEngine contain examples that show the direct integration with them.
Please refer to these examples to see how this all works out.
4 - Oct - 2017
Kashif
Hi, I am loading main.qml in my C++/Qt main file (main.cpp) using QQmlApplicationEngine. I am using WebEngineView (inside my main.qml file) and i load different HTML/JS pages e.g. onButtonClick. I use webchannel property of WebEngineView and register different QML objects that i need to access from HTML/JS.
I want to expose some objects' properties and methods of my C++/Qt objects via QWebChannel to HTML/JS. How can i go about it. Is it possible to use WebChannel of WebEngineView (main.qml) and register my C++/Qt objects from my main.cpp file. Or should a separate QWebChannel be defined in C++/Qt. Need help. Thanks.
4 - Oct - 2017
Milian Wolff
Make the C++/Qt objects accessible to QML (context property or any of the other options) and then register them on the WebChannel from the WebEngineView - no need for a separate QWebChannel in C++.
Cheers
3 - Nov - 2017
Neeraj Badal
Hi Millian,
May be the question wont be relevant in this post, but whenever i try to open a qml file remotely on a qtcreator designer, qtcreator crashes. This behavior is sometimes observed on program that use qml but not always otherwise when working on local system it runs smoothly
Thanks
15 - Nov - 2017
Milian Wolff
I don't see how this has anything to do with Qt WebChannel. Furthermore, always report bugs in bug trackers, not in blog post comments. See: https://bugreports.qt.io