Transcript
Page 1: Serving QML applications over the network

Serving QML applications over the network

Jeremy LainéWifirst

Page 2: Serving QML applications over the network

2 / 35

Jeremy Lainé

●Using Qt since 2001 (desktop, mobile, embedded)

●Occasional Qt contributor (QDnsLookup)

●Head of software development at Wifirst (ISP)

●Lead developer of a IM / VoIP app for Wifirst customers

Page 3: Serving QML applications over the network

3 / 35

Overview

1. Why serve applications over the network?

2. QML network transparency

3. Building your application

4. Deploying your application

Page 4: Serving QML applications over the network

4

1. Why serve applications over the network?

Page 5: Serving QML applications over the network

Typical application deployment

●Development

●Packaging

●In-house beta testing

●Push application to all users

●Repeat!

Each iteration requires per-platform installers and an update.Each iteration requires per-platform installers and an update.

Page 6: Serving QML applications over the network

6 / 35

Options for handling updates

●Manual updates●Most users cannot be bothered to update

●You end up with a heterogeneous installed base●Your cool new features don't reach your users!

●Automatic updates●Not all platforms have an “application store”

●Each platform requires specific packaging wok

●Usually requires elevated permissions (Windows UAC..)

Page 7: Serving QML applications over the network

7 / 35

Updates are hard!

Not convinced? Look at the Chrome and Firefox codebases!Not convinced? Look at the Chrome and Firefox codebases!

Page 8: Serving QML applications over the network

8 / 35

How about QML apps?

●C++ wrapper code:● has usual deployment constraints

●QML / Javascript code and resources:●fully cross-platform

●conveniently split into multiple files

●can be loaded over the network by QtQuick

Page 9: Serving QML applications over the network

9 / 35

Some benefits

●Faster iteration and testing

●Fix bugs after release!

●Progressive update roll-out

●Split testing for UI changes

●Time-limited changes (Christmas specials!)

Page 10: Serving QML applications over the network

10

2. QML network transparency

Page 11: Serving QML applications over the network

11 / 35

Loading QML from C++

QDeclarativeView (Qt4) and QQuickView (Qt5) support loading from an HTTP URL

int main(int argc, char *argv[]){ QApplication app(argc, argv);

QQuickView view; view.setSource(QUrl(“http://foo.com/main.qml”)); view.show();

return app.exec();}

Page 12: Serving QML applications over the network

12 / 35

QML “loader” elements

Built-in QML elements with a “source” property support HTTP URLs

●Image

●Loader

●FontLoader

Image { source: “http://foo.com/bar.img”}

Page 13: Serving QML applications over the network

13 / 35

Relative URLs

Relative URLs are resolved relative to the QML document's URL

You can use the same code locally and remotely!You can use the same code locally and remotely!

Image { source: “head.jpg”}

file:///home/bob/foo.qml

Image { source: “head.jpg”}

http://example.com/foo.qml

file:///home/bob/head.jpg

http://example.com/head.jpg

Page 14: Serving QML applications over the network

14 / 35

QML network transparency

●QML type declarations can be served over HTTP, but you need to list your types in a “qmldir” file:

●Javascript code can be served over HTTP

Button 1.0 Button.qmlCheckBox 1.0 CheckBox.qml

import “scripts/utils.js” as Utils

Page 15: Serving QML applications over the network

15 / 35

Translations

●Loading translations from QML is missing

●You can provide your own TranslationLoader and do

●A proposal for including it in Qt5

https://codereview.qt-project.org/#change,31864

TranslationLoader {source: “i18n/my_translation.qm”

onStatusChanged: {Console.log(“status is: “ + status);

}}

Page 16: Serving QML applications over the network

16

3. Building your application

Page 17: Serving QML applications over the network

17 / 35

General recommendations

●Split models and presentation

●The C++ code still needs traditional updates●Make the loader robust

●Keep the API simple

●Keep the API stable

●Serve all the rest on the fly●QML and Javascript code

●Resources (images, fonts, translations)

Page 18: Serving QML applications over the network

18 / 35

Application architecture

Application Plugins

main.qml

Button.qml

background.png

fontawesome.ttf

Local C++ code

Remote content

Page 19: Serving QML applications over the network

19 / 35

The application

●Creates the QML view

●Sets up the QNetworkAccessManager

●Loads a single “root” QML file over the network

●Can fallback to local files for offline use

Page 20: Serving QML applications over the network

20 / 35

Application / setting up QNAM

●Give your application a User-Agent●Helps track usage, or serve different content

●QtWebkit generated request already have a UA

●Specify the preferred language (Accept-Language)

●Set up a persistent network cache

●Configure HTTP pipelining

Page 21: Serving QML applications over the network

21 / 35

Application / caching

●QtQuick caches components + pixmaps (memory)

●QNAM supports “If-Modified-Since” but needs a persistent disk cache

class MyFactory : public QQmlNetworkAccessManagerFactory{public: QNetworkAccessManager* create(QObject* parent) { QNetworkAccessManager* manager = new QNetworkAccessManager(parent); QNetworkDiskCache* cache = new QNetworkDiskCache(manager); cache->setCacheDirectory(“/some/directory/”); manager->setCache(cache); return manager; }};

view->engine()->setNetworkAccessManagerFactory(new MyFactory());

Page 22: Serving QML applications over the network

22 / 35

Application / HTTP pipelining

●Splitting QML into files: good but incurs overhead

●HTTP/1.1 allows sending multiple requests without waiting for replies

●Particularly useful for high latency links

●Qt5 uses pipelining for all resources

●Qt4 only uses pipelining for pixmaps and fonts● subclass QNetworkAccessManager if needed

Page 23: Serving QML applications over the network

23 / 35

Application / offline use

●At startup, fall back to a bundled copy of your QML code if loading from network fails

●Catching errors later is harder..

void MyView::onStatusChanged(QQuickView::Status status){

if (status == QQuickView::Error && useNetwork) {useNetwork = false;setSource(QUrl(“qrc://main.qml”));

}}

Page 24: Serving QML applications over the network

24 / 35

Plugins

●Define data models and scriptable objects

●Keep the C++ code simple : if something can be done in QML instead, do it!

●Keep the API stable : if you change it, you will probably need different QML files

Page 25: Serving QML applications over the network

25 / 35

QML content

●Welcome to an asynchronous world!

var component = Qt.createComponent(source);if (component.status == Component.Loading)

component.statusChanged.connect(finishCreation);else

finishCreation();

function finishCreation() {if (component.status == Component.Ready) {

var object = component.createObject(parent);}

}

var component = Qt.createComponent(source);var object = component.createObject(parent); BAD

GOOD

Page 26: Serving QML applications over the network

26 / 35

QML content

●Review your timing assumptions!●Do not depend on objects loading in a set order

●Use Component.onCompleted with care

●Having lots of icons can be a problem, consider using web fonts like FontAwesome

Page 27: Serving QML applications over the network

27

4. Deploying your application

Page 28: Serving QML applications over the network

28 / 35

Hosting the QML code

●You have all the usual web hosting options●Run your own servers (nginx, apache, ..)

●Use cloud services

●Do load-balancing, fail-over, etc..

●QML files can be 100% static files, or even generated on the fly

Page 29: Serving QML applications over the network

29 / 35

Version your root URL

●Plan for multiple versions of your C++ app, as the API will probably change, e.g. :

http://example.com/myapp/1.0/main.qml

http://example.com/myapp/1.1/main.qml

●Alternatively, switch on User-Agent

Page 30: Serving QML applications over the network

30 / 35

Cache “consistency”

●Consider two related files Dialog.qml and Button.qml, which must be in the same version to work

●Caching can cause inconsistency

Dialog.qmlversion 1

App start 1 App start 2

Button.qmlversion 1

time

Button.qmlversion 1

User click 1 User click 2

Dialog.qmlversion 2

FAIL!

Page 31: Serving QML applications over the network

31 / 35

Cache “consistency”

●Your main.qml can load all subsequent contents from a subdirectory to “version” the QML code

●Layout:●main.qml

●RELEASE_ID/Button.qml

●RELEASE_ID/Dialog.qml

Page 32: Serving QML applications over the network

32 / 35

Security

●Make use of HTTPS to avoid your application loading malicious code (DNS hijacking)

●Make sure your certificates are valid!

●Some platforms or custom certificates will require adding your CA certificates

QSslSocket::addDefaultCaCertificates(“./myca.pem”);

Page 33: Serving QML applications over the network

33 / 35

Performance considerations

●Enable gzip compression for QML and JS files

●Set an Expires header to avoid QNAM re-checking all files on startups

●Serve from a cookie-less domain

Page 34: Serving QML applications over the network

34

5. Questions

Page 35: Serving QML applications over the network

35 / 35

Get the code

●Source code for the Wifirst IM / VoIP client

git clone git://git.wifirst.net/wilink.git


Top Related