Serving QML applications over the network Jeremy Lain Wifirst - - PowerPoint PPT Presentation

serving qml applications over the network jeremy lain
SMART_READER_LITE
LIVE PREVIEW

Serving QML applications over the network Jeremy Lain Wifirst - - PowerPoint PPT Presentation

Serving QML applications over the network Jeremy Lain Wifirst Jeremy Lain Using Qt since 2001 (desktop, mobile, embedded) Occasional Qt contributor (QDnsLookup) Head of software development at Wifjrst (ISP) Lead developer of a


slide-1
SLIDE 1

Serving QML applications over the network Jeremy Lainé Wifirst

slide-2
SLIDE 2

2 / 35

Jeremy Lainé

  • Using Qt since 2001 (desktop, mobile, embedded)
  • Occasional Qt contributor (QDnsLookup)
  • Head of software development at Wifjrst (ISP)
  • Lead developer of a IM / VoIP app for Wifjrst

customers

slide-3
SLIDE 3

3 / 35

Overview

  • 1. Why serve applications over the network?
  • 2. QML network transparency
  • 3. Building your application
  • 4. Deploying your application
slide-4
SLIDE 4

4

  • 1. Why serve applications over the network?
slide-5
SLIDE 5

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.

slide-6
SLIDE 6

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 specifjc packaging wok
  • Usually requires elevated permissions (Windows UAC..)
slide-7
SLIDE 7

7 / 35

Updates are hard! Not convinced? Look at the Chrome and Firefox codebases! Not convinced? Look at the Chrome and Firefox codebases!

slide-8
SLIDE 8

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 fjles
  • can be loaded over the network by QtQuick
slide-9
SLIDE 9

9 / 35

Some benefjts

  • Faster iteration and testing
  • Fix bugs after release!
  • Progressive update roll-out
  • Split testing for UI changes
  • Time-limited changes (Christmas specials!)
slide-10
SLIDE 10

10

  • 2. QML network transparency
slide-11
SLIDE 11

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(); }

slide-12
SLIDE 12

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” }

slide-13
SLIDE 13

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

slide-14
SLIDE 14

14 / 35

QML network transparency

  • QML type declarations can be served over HTTP,

but you need to list your types in a “qmldir” fjle:

  • Javascript code can be served over HTTP

Button 1.0 Button.qml CheckBox 1.0 CheckBox.qml import “scripts/utils.js” as Utils

slide-15
SLIDE 15

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”

  • nStatusChanged: {

Console.log(“status is: “ + status); } }

slide-16
SLIDE 16

16

  • 3. Building your application
slide-17
SLIDE 17

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 fmy
  • QML and Javascript code
  • Resources (images, fonts, translations)
slide-18
SLIDE 18

18 / 35

Application architecture

Application Plugins main.qml Button.qml background.png fontawesome.ttf Local C++ code Remote content

slide-19
SLIDE 19

19 / 35

The application

  • Creates the QML view
  • Sets up the QNetworkAccessManager
  • Loads a single “root” QML fjle over the network
  • Can fallback to local fjles for offmine use
slide-20
SLIDE 20

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
  • Confjgure HTTP pipelining
slide-21
SLIDE 21

21 / 35

Application / caching

  • QtQuick caches components + pixmaps (memory)
  • QNAM supports “If-Modifjed-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());

slide-22
SLIDE 22

22 / 35

Application / HTTP pipelining

  • Splitting QML into fjles: 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
slide-23
SLIDE 23

23 / 35

Application / offmine 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”)); } }

slide-24
SLIDE 24

24 / 35

Plugins

  • Defjne 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 fjles

slide-25
SLIDE 25

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

slide-26
SLIDE 26

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

slide-27
SLIDE 27

27

  • 4. Deploying your application
slide-28
SLIDE 28

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 fjles can be 100% static fjles, or even

generated on the fmy

slide-29
SLIDE 29

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
slide-30
SLIDE 30

30 / 35

Cache “consistency”

  • Consider two related fjles Dialog.qml and

Button.qml, which must be in the same version to work

  • Caching can cause inconsistency

Dialog.qml version 1 App start 1 App start 2 Button.qml version 1 time Button.qml version 1 User click 1 User click 2 Dialog.qml version 2 FAIL!

slide-31
SLIDE 31

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
slide-32
SLIDE 32

32 / 35

Security

  • Make use of HTTPS to avoid your application

loading malicious code (DNS hijacking)

  • Make sure your certifjcates are valid!
  • Some platforms or custom certifjcates will require

adding your CA certifjcates

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

slide-33
SLIDE 33

33 / 35

Performance considerations

  • Enable gzip compression for QML and JS fjles
  • Set an Expires header to avoid QNAM re-checking

all fjles on startups

  • Serve from a cookie-less domain
slide-34
SLIDE 34

34

  • 5. Questions
slide-35
SLIDE 35

35 / 35

Get the code

  • Source code for the Wifjrst IM / VoIP client

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