Skip to content
r0ller edited this page May 31, 2021 · 23 revisions

This is a sketch for a cross-platform architecture where the frontend is qml and the backend is c++. I know that qt is cross-platform by design but I was looking for a design with which I can have the same frontend and backend everywhere even in a client-server setup. Besides that I also wanted more freedom (not being bound to a specific android ndk version) but also wanted to keep qml as a ui even for non qt c++ backend. So I started by decoupling the qml ui and looked for a design pattern with which the communication can be solved in each scenario. Finally, I chose the command design pattern and the scenarios are as follows:

qwa architecture

  • native (desktop): has normal qml ui which if necessary (say on click of a button), passes a command object (stringified json object) to an exposed method which passes it on to the backend. The backend here is a library that exports a function that receives the command and returns the response. The library itself implements the rest of the command design pattern. The response is returned to the ui by invoking a qml method.

  • webapp: this is a simple webassembly build of the native version with the addition that a static library needs to be created for the backend with emar. Move the red rectangle by clicking here and there in the online webassembly demo. NOTE: I decided to recompile the project for Node JS so that one can just clone the project and start it like 'node index.js' as it's the most interesting scenario so the qml part of this webapp demo still works but the message passing between frontend and backend broke since the backend lib is now compiled for Node JS.

  • android: has a webassembly build of the same qml ui in a webview that passes the command json object via webmessage channel through the webview to the android java layer which passes it on to the c++ backend library via java native interface. The backend is the same c++ library but crosscompiled for android. The response is returned to the qml ui via webmessage channel. In this case only an android wrapper app is necessary that handles a webview for the ui and handles the "backend" calls. Theoretically, the same can be done on iOS as safari has the webmessage channel concept as well but I'm not familiar with that platform at all. Download android app here.

  • nodejs: has a webassembly build of the same qml ui which is loaded on a GET request from the nodejs server. When necessary, the qml ui posts a command json object in a request to the appropriate endpoint of the nodejs server where the request is handled and the command json object is passed on to either a webassembly build of the backend library or a nodejs N-API C++ addon that wraps the backend logic. The response is then returned to the client from nodejs and then to the qml ui either via the webassembly built qml method invocation or via emscripten inline javascript. You should be able to test this scenario by connecting to your localhost:8080 port via a browser AFTER cloning the project and issueing in the qwa_node directory:
    node index.js

As this is currently just a sketch and there's no real command json object sent (and no command design pattern in place) when you click on the text "Hello world" only some test strings are sent like "Hello from QML" to backend and the response is "Returned from backend: Hello from QML".

All builds are debug builds without any optimization so the android app load time is damn slow but afterwards it works just like the native one. I have not yet tweaked the project file so you need to comment/uncomment a few defines in the qmlwasm1 and in the qwa_pure_backend project file configuration to get a successful webassembly or native build. The following three defines determine the build:

__ANDROID__
__NODEJS__
__NATIVE__

The main parts of the repo are:

  • qmlwasm1: contains the qml ui logic (depends on qwa_pure_backend when compiled for native)
  • qwa_pure_backend: contains the backend logic. Building the qwa_pure_backend was not smooth as the project file settings did not make it to the effective qmake call so there's a manual_build.sh and a build_wasm_lib.sh in the build-qwa_pure_backend-Debug directory.
  • Android/qmlwasm1: contains a full integration of the ui and backend in an android app
  • qwa_backend: qt library variant of qwa_pure_backend but it does not work (yet) on android for whatever reasons
  • qwa_node: contains the relevant node js files. Communication currently uses emscripten_async_wget2_data which cannot send json only urlencoded data but if you wish, you can change the code in qmlwasm1 and here in index.js to use the fetch API to send pure json.
Clone this wiki locally