THE PROGRESSION OF WEB APPS NLHTML5 @ DE VOORHOEDE, 20TH OCTOBER 2016

THE PROGRESSION OF WEB APPS NLHTML5 @ DE VOORHOEDE, 20TH OCTOBER 2016

THE PROGRESSION OF WEB APPS

THE PROGRESSION OF WEB APPS

PROGRESSIVE WEB APPS

Photo by Daniel Appelquist

PROGRESSIVE

RESPONSIVE

CONNECTIVITY INDEPENDENT

APP-LIKE

FRESH

SAFE

DISCOVERABLE

RE-ENGAGEABLE

INSTALLABLE

LINKABLE

PROGRESSIVE

WEB APP

RESPONSIVE

airhorner.com

CONNECTIVITY INDEPENDENT

MENU Where is my navigation? Click on the hamburger menu to get access to all of the navigation options. APP-LIKE

APP-LIKE

FRESH

FRESH

SAFE

DISCOVERABLE

Hi there! I’m a Web App!

This is a testnot Something pushmessage very important on acceptation. has happened You have Battery is 4almost app updates empty, connect your charger available RE-ENGAGEABLE Someone you hardly know posted what he just ate

INSTALLABLE

airhorner.com The Airhorner × airhorner.com ADD TO HOMESCREEN

LINKABLE

Airhorner

Airhorner no results found

https://airhorner.com

THIS IS NOT A NEW IDEA

“ The full Safari engine is inside of iPhone. And so, you can write amazing Web 2.0 and Ajax apps that look exactly and behave exactly like apps on the iPhone. And these apps can integrate perfectly with iPhone services. — Steve Jobs, 2007

“ The fundamental problem on the iPhone is not Apple’s App Store approval policies, but the iPhone developers’ arrogant disdain for Web technologies. I reviewed the apps I have on my iPhone, and most can be released as a Web app right now. — Peter Paul Koch, 2009

“ The fundamental problem on the iPhone is not Apple’s App Store approval policies, but the iPhone developers’ arrogant disdain for Web technologies. I reviewed the apps I have on my iPhone, and most can be released as a Web app right now. — Peter Paul Koch, 2009

✓ PROGRESSIVE ✓ RESPONSIVE ✓ CONNECTIVITY INDEPENDENT ✓ APP-LIKE ✓ SAFE ✓ DISCOVERABLE ✓ INSTALLABLE ✓ LINKABLE

LOTS OF UGLY HACKS

LOTS OF BROWSER QUIRKS

NON-STANDARD API’S

NO DEVICE API’S

BUILDING NATIVE APPS USING WEB TECHNOLOGY

WHY?

WE KNOW HTML, CSS AND JAVASCRIPT

CROSS PLATFORM DEVELOPMENT

GET ACCESS TO NATIVE API’S

THE APP STORE

$ € ¥ £ € ₽ kr. ¥ ‫دج‬ ¥ $€ £ ₽

PACKAGED WEB APPS

}

HOSTED WEB APPS

  • URL of the hosted web app }

2007

application.xml <application xmlns="http://ns.adobe.com/air/application/2.5"> <id>nl.salonhub.Salonhub</id> <filename>Salonhub</filename> <name>Salonhub</name> <versionNumber>6.0.356</versionNumber> <description>De flexibele en complete oplossing voor uw kapsalon</description> <initialWindow> <content>platform/air/app/index.html</content> <width>1024</width> <height>768</height>

adt -package -storetype pkcs12 -keystore cert.p12 -storepass ****** dist/air/Salonhub-6.0.365.air build/air/application.xml -C build/air assets external lib platform settings.js

Salonhub.air

2007

2007

2009

Vibration Dialogs Network Information Camera Device Motion Battery Status Splashscreen DEVICE API’S Files Statusbar Device Orientation Media Capture Geolocation File Transfers Media

PLUGINS

“ PhoneGap is a polyfill, and the ultimate purpose of PhoneGap is to cease to exist — Brian LeRoux

2009

2012 chrome app

chromebook

chrome web store

2012 chrome app

2013

chromium +

launch.js const electron = require('electron'); const app = electron.app; let mainWindow; function createWindow () { mainWindow = new electron.BrowserWindow({ width: 800, height: 600 }); mainWindow.loadURL('file://' + __dirname + '/app/index.html'); mainWindow.on('closed', () => { mainWindow = null }); } app.on('ready', () => { createWindow(); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); }

2013

2013

2014 Universal Windows Platform

npm install -g manifoldjs manifoldjs https://airhorner.com -d ~/Projects -p windows10 manifoldjs package ~/Projects/AirHorner/windows10

UNIVERSAL WINDOWS APPS HAVE ACCESS TO THE UNIVERSAL WINDOWS API

DEPLOY ON DESKTOP, MOBILE AND XBOX ONE

2014 Universal Windows Platform

AND MANY MORE…

BUT…

DEPENDANT ON THIRD PARTIES

NOT PART OF THE WEB

PROGRESSIVE WEB APPS

WEB MANIFEST

index.html <!doctype> <html> <head> <title>HTML5test - How well does your browser support HTML5?</title>

index.html <!doctype> <html> <head> <title>HTML5test - How well does your browser support HTML5?</title> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black">

index.html <!doctype> <html> <head> <title>HTML5test - How well does your browser support HTML5?</title> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <link <link <link <link <link <link <link <link rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png"> sizes="114x114" href="/apple-icon-114x114.png"> sizes="72x72" href="/apple-icon-72x72.png"> sizes="144x144" href="/apple-icon-144x144.png"> sizes="60x60" href="/apple-icon-60x60.png"> sizes="120x120" href="/apple-icon-120x120.png"> sizes="76x76" href="/apple-icon-76x76.png"> sizes="152x152" href="/apple-icon-152x152.png">

<!doctype> <html> <head> <title>HTML5test - How well does your browser support HTML5?</title> <meta name="apple-mobile-web-app-capable" index.htmlcontent="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <link <link <link <link <link <link <link <link rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png"> sizes="114x114" href="/apple-icon-114x114.png"> sizes="72x72" href="/apple-icon-72x72.png"> sizes="144x144" href="/apple-icon-144x144.png"> sizes="60x60" href="/apple-icon-60x60.png"> sizes="120x120" href="/apple-icon-120x120.png"> sizes="76x76" href="/apple-icon-76x76.png"> sizes="152x152" href="/apple-icon-152x152.png">

<!doctype> <html> <head> <title>HTML5test - How well does your browser support HTML5?</title> <meta name="apple-mobile-web-app-capable" index.htmlcontent="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <link <link <link <link <link <link <link <link rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png"> sizes="114x114" href="/apple-icon-114x114.png"> sizes="72x72" href="/apple-icon-72x72.png"> sizes="144x144" href="/apple-icon-144x144.png"> sizes="60x60" href="/apple-icon-60x60.png"> sizes="120x120" href="/apple-icon-120x120.png"> sizes="76x76" href="/apple-icon-76x76.png"> sizes="152x152" href="/apple-icon-152x152.png">

<meta name="mobile-web-app-capable" content="yes"> <meta name="theme-color" content="#0092bf">

<!doctype> <html> <head> <title>HTML5test - How well does your browser support HTML5?</title> <meta name="apple-mobile-web-app-capable" index.htmlcontent="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <link <link <link <link <link <link <link <link rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png"> sizes="114x114" href="/apple-icon-114x114.png"> sizes="72x72" href="/apple-icon-72x72.png"> sizes="144x144" href="/apple-icon-144x144.png"> sizes="60x60" href="/apple-icon-60x60.png"> sizes="120x120" href="/apple-icon-120x120.png"> sizes="76x76" href="/apple-icon-76x76.png"> sizes="152x152" href="/apple-icon-152x152.png">

<meta name="mobile-web-app-capable" content="yes"> <meta name="theme-color" content="#0092bf"> <link <link <link <link <link rel="icon" rel="icon" rel="icon" rel="icon" rel="icon" type="image/png" type="image/png" type="image/png" type="image/png" type="image/png" href="/icon-16x16.png" sizes="16x16"> href="/icon-32x32.png" sizes="32x32"> href="/icon-96x96.png" sizes="96x96"> href="/icon-160x160.png" sizes="160x160"> href="/icon-196x196.png" sizes="196x196">

<link <link <link <link <link <link rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png"> sizes="144x144" href="/apple-icon-144x144.png"> sizes="60x60" href="/apple-icon-60x60.png"> sizes="120x120" href="/apple-icon-120x120.png"> sizes="76x76" href="/apple-icon-76x76.png"> index.html sizes="152x152" href="/apple-icon-152x152.png"> <meta name="mobile-web-app-capable" content="yes"> <meta name="theme-color" content="#0092bf"> <link <link <link <link <link rel="icon" rel="icon" rel="icon" rel="icon" rel="icon" type="image/png" type="image/png" type="image/png" type="image/png" type="image/png" href="/icon-16x16.png" sizes="16x16"> href="/icon-32x32.png" sizes="32x32"> href="/icon-96x96.png" sizes="96x96"> href="/icon-160x160.png" sizes="160x160"> href="/icon-196x196.png" sizes="196x196">

<link <link <link <link <link <link rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png"> sizes="144x144" href="/apple-icon-144x144.png"> sizes="60x60" href="/apple-icon-60x60.png"> sizes="120x120" href="/apple-icon-120x120.png"> sizes="76x76" href="/apple-icon-76x76.png"> index.html sizes="152x152" href="/apple-icon-152x152.png"> <meta name="mobile-web-app-capable" content="yes"> <meta name="theme-color" content="#0092bf"> <link <link <link <link <link rel="icon" rel="icon" rel="icon" rel="icon" rel="icon" type="image/png" type="image/png" type="image/png" type="image/png" type="image/png" href="/icon-16x16.png" sizes="16x16"> href="/icon-32x32.png" sizes="32x32"> href="/icon-96x96.png" sizes="96x96"> href="/icon-160x160.png" sizes="160x160"> href="/icon-196x196.png" sizes="196x196"> <meta name="application-name" content="HTML5test"> <meta name="msapplication-TileColor" content="#0092bf"> <meta name="msapplication-TileImage" content="/mstile-144x144.png">

PLACE EVERYTHING IN A SEPARATE JSON FILE

manifest.json { "name": "HTML5test", "theme_color": "#0092bf", "display": "standalone", "icons": [ { "src": "/icon-192x192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/icon-256x256.png", "sizes": "256x256", "type": "image/png" }, { "src": "/icon-512x512.png", "sizes": "512x512", "type": "image/png" }

APP NAME ICONS THEME COLORS SETTINGS

LAUNCH FULL SCREEN { "display": "standalone" }

LIMIT SCREEN ORIENTATION { "orientation": "portrait" }

START A DIFFERENT URL { "start_url": "standalone.html" }

index.html <!doctype> <html> <head> <title>HTML5test - How well does your browser support HTML5?</title> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black"> <link <link <link <link <link <link <link <link rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" sizes="57x57" href="/apple-icon-57x57.png"> sizes="114x114" href="/apple-icon-114x114.png"> sizes="72x72" href="/apple-icon-72x72.png"> sizes="144x144" href="/apple-icon-144x144.png"> sizes="60x60" href="/apple-icon-60x60.png"> sizes="120x120" href="/apple-icon-120x120.png"> sizes="76x76" href="/apple-icon-76x76.png"> sizes="152x152" href="/apple-icon-152x152.png">

<meta name="mobile-web-app-capable" content="yes"> <meta name="theme-color" content="#0092bf"> <link rel="icon" type="image/png" href="/icon-16x16.png" sizes="16x16">

<link <link <link <link <link <link rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png"> sizes="144x144" href="/apple-icon-144x144.png"> sizes="60x60" href="/apple-icon-60x60.png"> sizes="120x120" href="/apple-icon-120x120.png"> sizes="76x76" href="/apple-icon-76x76.png"> index.html sizes="152x152" href="/apple-icon-152x152.png"> <meta name="mobile-web-app-capable" content="yes"> <meta name="theme-color" content="#0092bf"> <link <link <link <link <link rel="icon" rel="icon" rel="icon" rel="icon" rel="icon" type="image/png" type="image/png" type="image/png" type="image/png" type="image/png" href="/icon-16x16.png" sizes="16x16"> href="/icon-32x32.png" sizes="32x32"> href="/icon-96x96.png" sizes="96x96"> href="/icon-160x160.png" sizes="160x160"> href="/icon-196x196.png" sizes="196x196"> <meta name="application-name" content="HTML5test"> <meta name="msapplication-TileColor" content="#0092bf"> <meta name="msapplication-TileImage" content="/mstile-144x144.png">

<link <link <link <link <link <link rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" rel="apple-touch-icon" sizes="72x72" href="/apple-icon-72x72.png"> sizes="144x144" href="/apple-icon-144x144.png"> sizes="60x60" href="/apple-icon-60x60.png"> sizes="120x120" href="/apple-icon-120x120.png"> sizes="76x76" href="/apple-icon-76x76.png"> index.html sizes="152x152" href="/apple-icon-152x152.png"> <meta name="mobile-web-app-capable" content="yes"> <meta name="theme-color" content="#0092bf"> <link <link <link <link <link rel="icon" rel="icon" rel="icon" rel="icon" rel="icon" type="image/png" type="image/png" type="image/png" type="image/png" type="image/png" href="/icon-16x16.png" sizes="16x16"> href="/icon-32x32.png" sizes="32x32"> href="/icon-96x96.png" sizes="96x96"> href="/icon-160x160.png" sizes="160x160"> href="/icon-196x196.png" sizes="196x196"> <meta name="application-name" content="HTML5test"> <meta name="msapplication-TileColor" content="#0092bf"> <meta name="msapplication-TileImage" content="/mstile-144x144.png"> <link rel="manifest" href="/manifest.json">

BROWSER SUPPORT Chrome 39 Opera 32

DEVICE API’S

VIBRATION navigator.vibrate(200); navigator.vibrate([100, 200, 200, 200, 500]);

CAMERA & MICROPHONE navigator.getUserMedia( { audio: true, video: { width: 1280, height: 720 } }, function(stream) { }, function(err) { } });

BATTERY navigator.getBattery().then(function(battery) { battery.addEventListener('chargingchange', function() { console.log(battery.charging); }); battery.addEventListener('levelchange', function() { console.log(battery.level); }); });

GEOLOCATION DEVICE MOTION DEVICE ORIENTATION AMBIENT LIGHT BLUETOOTH

SERVICE WORKERS

“ Application Cache is a Douchebag! — Jake Archibald

? ×

if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); }

×

THE SERVICE WORKER RUNS JAVASCRIPT CODE :-)

sw.js self.addEventListener('install', function(event) { // Perform install steps });

sw.js self.addEventListener('install', function(event) { event.waitUntil( caches.open('v1').then(function(cache) { return cache.addAll([ '/index.html', '/styles/main.css', '/scripts/main.js' ]); }) ); });

return cache.addAll([ '/index.html', '/styles/main.css', '/scripts/main.js' ]); }) ); }); sw.js

return cache.addAll([ '/index.html', '/styles/main.css', '/scripts/main.js' ]); }) sw.js ); }); self.addEventListener('fetch', function(event) { // Intercept network requests });

return cache.addAll([ '/index.html', '/styles/main.css', '/scripts/main.js' ]); }) sw.js ); }); self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { if (response) { return response; } return fetch(event.request); } ) ); });

THE SERVICE WORKER IS INDEPENDENT OF YOUR WEBPAGE

BROWSER SUPPORT Chrome 40 Opera 27 Firefox 44 Samsung 4 Edge (behind flag)

PUSH NOTIFICATIONS

WEB PUSH API WEB PUSH PROTOCOL WEB NOTIFICATIONS SERVICE WORKERS

navigator.serviceWorker.ready.then(function(sw) { sw.pushManager.subscribe().then(function(subscription) { // Send subscription to server }) })

Send the subscription data to our server, including the URL of the push server

The webpage is closed and the service worker is sleeping

The server has new information for the user

The server sends a message to the push server using the Web Push protocol

The push server wakes up the service worker

self.addEventListener('push', function(event) { // We received a push message });

(optional)

self.registration.showNotification('Attention!', { body: 'Push message received', icon: 'icon.png' }); (optional)

The webpage is still closed and the service worker is sleeping again

BROWSER SUPPORT Chrome 42 Opera 30 Firefox 44 Samsung 4 Edge (behind flag)

WEB PAYMENTS

Start payment process by clicking a button in your app

Start payment process by clicking a button in your app var methodData = [ { supportedMethods: ["visa", "mastercard"] } ];

var details = { displayItems: [ { label: "Donation", amount: { currency: "USD", value : "55.00" } } ], total: { label: "Total", amount: { currency: "USD", value : "55.00" } } }; Start payment process by clicking a button in your app

var request = new PaymentRequest( methodData, // required payment method data details // required transaction information );

request.show().then(function(response) { // success }).catch(function(err) { // failed });

Select your payment method or use the default

Enter your CVC code or confirm with your fingerprint

Done!

BROWSER SUPPORT Chrome Samsung 4 Edge (coming soon) (behind flag)

BUT WHAT ABOUT THE DESKTOP?

BROWSER DEVELOPMENT IS DRIVEN BY MOBILE

BUT…

NATIVE PWA SUPPORT IN THE WINDOWS STORE

NATIVE PWA SUPPORT IN THE WINDOWS STORE

BUT WHAT ABOUT APPLE?

THIS IS NOT A GOOGLE THING

BUT…

× ?

THE OLD HACKS STILL WORK

MAYBE, HOPEFULLY, POSSIBLY THIS WILL CHANGE IN THE FUTURE

OR NOT

THANK YOU! @HTML5TEST

18 NOVEMBER, LONDON Dylan Schiemann, Christian Heilmann, Mark Wubben, Jonathan Fielding and me