sencha roadshow 2017: build progressive web apps with ext js and cmd

41

Upload: sencha

Post on 23-Jan-2018

268 views

Category:

Technology


5 download

TRANSCRIPT

Build Progressive Web Appswith Ext JS and Cmd

Olga Petrova

Agenda

PWA definition•

PWA vs Hybrid vs Native•

PWA architecture•

Web Application Manifest-

Caching using Service Worker-

Web Push Notifications-

Access to Native Hardware-

3

PWA

A progressive web app is a model for creating app-like experiences using the latest

Web technologies progressively

4

PWA features

• Instant loading

• Discoverable

• Network independent

• Responsive

• Installable

• Secure

• Linkable

• Re-engageable (Push messages)

• Work everywhere

• Fast

5

✔️

✔️

✔️

✔️

✔️

✔️

✔️

PWA vs Hybrid

6

PWA Hybrid

Store distribution

Packaging and signing

“Native” plugins

Best of Web and Native

Linkable•

Discoverable•

Easy to deploy•

Easy to update•

Standards•

Work everywhere•

Offline Access•

Installed Icon•

Push Notifications•

Full Screen Experience•

Fast UI•

Access to sensors and hardware•

7

Progressive Enhancement

It is a web application1.

Add native installation2.

Add offline3. -mode support

Add Web Push notifications4.

Add hardware and platform access5.

8

Steps to implement

• Normal fast Web Application

• Add Web Application Manifest

• Cache app shell and data (Service Worker)

• Offer Web Notifications (Service Worker)

• Offer device specific experience

9

“progressive” config in app.json

• Add Web Application Manifest

• Register Service Worker

10

Web Application Manifest

Web App Manifest

JSON file•

Meta Data for PWA•

"Add to Home Screen" banner•

12

"Add to Home Screen" banner requirements

Service Worker•

Web App Manifest•

HTTPS•

Second visit in a short period of time•

13

Web App Manifest configurations

"progressive": {

"manifest": {

"name": "My Application",

"short_name": "My App",

"icons": [{

"src": "resources/icon-small.png",

"sizes": "96x96"

}, …],

"theme_color": "#054059",

"background_color": "#054059",

"display": "standalone",

"orientation": "portrait",

"start_url": "/index.html"

}

}

app.json

Service Worker

Service Worker

Javascript thread that is working outside of the browser window

16

Caching with Service Worker

• Automatically register SW (using sw-precache)

• Automatically cache an app shell

- HTML, Javascript, CSS, fonts, images

• Cache resources

- by adding @sw-cache comments

- configure “runtimeCaching” in app.json file

17

// @sw-cache

Ext.define('App.store.UpcomingEvents', {

extend: 'Ext.data.Store',

proxy: {

type: 'ajax',

// @sw-cache

url: '/api/upcoming-events.json',

reader: {

type: 'json'

}

}

});UpcomingEvents.js

// @sw-cache

Ext.define('App.model.Event', {

extend: 'Ext.data.Model',

fields: ['id', 'name', 'date'],

proxy: {

type: 'rest',

// @sw-cache { urlPattern: "\\/api\\/events\\/\\d+" }

url : '/events'

}

}); Event.js

Controlling Cache Behavior

urlPattern•

handler: • networkFirst / cacheFirst / fastest / cacheOnly / networkOnly

options•

debug-

networkTimeoutSeconds-

cache-

name•

maxEntries•

maxAgeSeconds•

20

Controlling Cache Behavior

Ext.define('App.model.Event', {

extend: 'Ext.data.Model',

fields: ['id', 'name', 'date'],

proxy: {

type: 'rest',

// @sw-cache { urlPattern: "\\/api\\/events\\/\\d+", options: { cache: { name: 'events', maxEntries: 10 } } }

url : '/events'

}

});Event.js

serviceWorker config in app.json

"serviceWorker": {"runtimeCaching": [

{

"urlPattern": "\\/api\\/events\\/\d+",

"options": {

"cache": {

"name": "events",

"maxEntries": 10

}

}

}, …

]

}

app.json

Web Push Notifications

Web Push Notifications

Gives web applications the ability to

receive messages pushed to them

from a server at any time

Round 1: Service Worker Registration

WebApp

Service Worker

Browser

Push ServerApp Server

Register

ServiceWorkerRegistration

Page Load

Round 1: ServiceWorker Registration

if ('serviceWorker' in navigator) {

if ('PushManager' in window) {

navigator.serviceWorker.register('ServiceWorker.js').then(function(registration) {

//state initializing

});

.catch(function() {

//error handling

});

} else {

//error handling

}

} else {

//error handling

}WebApp

Round 2: Subscription

WebApp

Service Worker

Browser

Push ServerApp Server

Subscribe

PushSubscription

Subscribe push subscriptionsave PushSubscription

User is ready to subscribe

Round 2: Subscription

navigator.serviceWorker.ready.then(function(registration) {

registration.pushManager.subscribe({

userVisibleOnly: true,

applicationServerKey: urlBase64ToUint8Array('...')

})

.then(function(subscription) {

// The subscription was successful

savePushSubscription(subscription);

})

.catch(function(e) {

//error handling

});

});WebApp

Round 3: Push Message

WebApp

Service Worker

Browser

Push ServerApp Server

push message

push message

push message

Something urgent and relevant happened

Round 3: Additional Headers

POST /{user_identifier} HTTP/1.1

Host: {push_server_url}

Prefer: respond-async

TTL: 15

Urgency: high

Topic: upd

Content-Type: text/plain;charset=utf8

Content-Length: 36

{encrypted_message} AppServer

Round 3: Push Message

self.addEventListener('push', function(event) {

var data = event.data.json();

event.waitUntil(self.registration.showNotification(data.title, {

body: data.body,

icon: data.icon,

tag: data.tag

}));

}); ServiceWorker

Round 3: Handle Notification

self.addEventListener('notificationclick', function(event) {

event.notification.close();

event.waitUntil(clients.openWindow('http://mywebsite.com'));

});

ServiceWorker

Round 4: Unsubscription

WebApp

Service Worker

Browser

Push ServerApp Server

unsubscribe

OK

unsubscribe OKremove PushSubscription

User wants to unsubscribe

Round 4: Unsubscription

registration.pushManager.getSubscription().then(function(subscription) {

if (subscription) {

return subscription.unsubscribe().then(function(successful) {

removePushSubscription(subscription);

}).catch(function(e) {

//error handling

});

}

})

.catch(function(error) {

//error handling

}) WebApp

Access to Hardware

Access to Native Hardware

• Geolocation

• Barcode detection

• WebShare

• WebCrypto

• WebSpeech API

• Device Orientation

• Device Motion API

• Proximity Sensor

• Light Sensor

• Clipboard API

• Battery Status API

• Presentation API

• Gamepad API

• WebVR

• 3d video

• HTML Media Capture

• Web RTC

Capture a photo using Web Camera

View

{xtype : 'video',reference: 'video'

},{

xtype: 'button',text: 'Capture',handler: 'onCaptureTap'

},{

xtype: 'd3-canvas',reference: 'canvas'

}

Capture a photo using Web Camera

onDialogShow: function () {

var player = this.lookup('video'),

handleSuccess = function(stream) {

player.media.dom.srcObject = stream;

};

navigator.mediaDevices.getUserMedia({video: true})

.then(handleSuccess);

},

onCaptureTap: function () {

var player = this.lookup('video'),

snapshotCanvas = this.lookup('canvas'),

context = snapshotCanvas.context2D;

context.drawImage(player.media.dom, 0, 0, width, height);

} ViewController

Progressive Enhancement

1. It is a web application

2. Add native installation

3. Add offline-mode support

4. Add Web Push notifications

5. Add hardware and platform access

39

Sample Application

https://github.com/olga-petrova/PWA

40