May 15, 2015
Web versus native
Chris Mills // Mozilla [email protected] // @chrisdavidmills
don’t worry about taking notes:
๏ These slides are all at slideshare.net/chrisdavidmills
๏ developer.mozilla.org
๏ @chrisdavidmills
๏ #mdn irc channel on mozilla irc
๏ [email protected] mailing list
๏ heavy metal drummer turned web nerd
๏ tech writer @ mozilla
๏ web tinkerer (HTML, CSS, JS)
๏ accessibility whiner
๏ educator
who am i?
mdn!!
what’s the problem?
web versus native, the age-old struggle
the usual arguments
native is better?
๏ faster?
๏ offine?
๏ more integrated, consistent experience?
๏ better developer ecosystem/tools?
๏ more secure?
the usual arguments
๏ web apps accessing other apps?
๏ web apps accessing camera contacts SMS/MMs dialler??
app ecosystem
Firefox os
We have this firefox os thing!
๏ open source project: everyone can get involved
๏ everything runs on the gecko engine
๏ Gaia: UI and suite of default apps
๏ Gonk: the underlying kernel/haL
installable apps
not a new phenomenon, but...
๏ pretty recent concept for web technologies
๏ manifest file defines app (manifest.webapp)
๏ installation controlled by app installation and management apis
{ "version": "0.1", "name": "To-do alarms", "description": "My awesome open web app", "launch_path": "/index.html", "icons": { "128": "/img/icon-128.png" }, "developer": { "name": "Chris Mills", "url": "http://yourawesomeapp.com" }, "locales": { "es": { "description": "Su nueva aplicación impresionante Open Web", "developer": { "url": "http://yourawesomeapp.com" } }, "it": {
manifest example
var manifest_url = location.href.substring(0, location.href.lastIndexOf("/")) + "/manifest.webapp"; function install() { // install the app var install = navigator.mozApps.install(manifest_url); install.onsuccess = function(data) { // App is installed, do something if you like }; install.onerror = function() { // App wasn't installed, info is in // install.error.name alert(install.error.name); }; };
installation example
app types
Apps can be:
๏ hosted: just like a normal web site, but with a manifest and install
functionality
๏ packaged: zipped up, hosted somewhere (like the firefox
marketplace), verified
app payments
you can charge money for web apps
๏ payments api uses payment providers like bango
๏ receipt verification to make sure payments are completed
๏ in-app payments also available (fxPay, mozpay)
web runtime
web rt allows app installation on other platforms
๏ apk factory for android apps, which include native api equivalents
where possible
๏ similar native wrappers for desktop platforms
๏ firefox marketplace/Firefox will generate these
developer experience
developer experience
we want to give the web a first class development experience,
alongside native ecosystems:
๏ documentation
๏ developer tools
๏ frameworks, templates, libraries
documentation
announce new things, provide useful references, give
recommendations:
๏ hacks blog
๏ mdn (app center)
developer tools
developer tools
๏ firefox’s standard toolbox
๏ app manager webide
๏ remote debugging using connect...
๏ you can run gaia on the desktop with firefox mulet
๏ node-firefox
webide
frameworks and libraries
ready made code to make development easier
๏ mortar app templates
๏ Web components
๏ firefox os boilerplate app
๏ phonegap support for firefox os
๏ and of course, ember, angular, backbone, yadda yadda
(device) apis
make it work on the web*...
*ok, ok, using web technologies!
apis!!!
we want to control everything using web technology
๏ apis to handle access to device hardware, system functions, etc.
๏ security handled by permissions, in the manifest
api permissions
different apis have different permission levels:
๏ common apis can be accessed by any app
๏ privileged apis can only be used in packaged, verified apps (e.g.
contacts, camera, device storage)
๏ internal (certified) apis can only be used by vendor-installed apps
(e.g. sms, dialer, bluetooth)
var pick = new MozActivity({ name: "pick", data: { type: ["image/png", "image/jpg", "image/jpeg"] } });
web activities (intents)
web activities
pick.onsuccess = function () { // Create image and set the returned blob as the src var img = document.createElement("img"); img.src = window.URL.createObjectURL(this.result.blob); // Present that image in your app var imagePresenter = document.querySelector("#image-presenter"); imagePresenter.appendChild(img); }; pick.onerror = function () { // If an error occurred or the user canceled the activity alert("Can't view the image!"); };
web activities
var img = '/to-do-notifications/img/icon-128.png'; var text = 'HEY! Your task "' + title + '" is now overdue.'; var notification = new Notification('To do list', { body: text, icon: img });
notification
window.navigator.vibrate(200); // vibrate for 200ms
window.navigator.vibrate([100,30,100,30,100,200,200,30,200,30,200,200,100,30,100,30,100]); // Vibrate 'SOS' in Morse.
vibration
window.addEventListener('devicelight', function(event) { var html = document.getElementsByTagName('html')[0];
if (event.value < 50) { html.classList.add('darklight'); html.classList.remove('brightlight'); } else { html.classList.add('brightlight'); html.classList.remove('darklight'); } });
ambient light events
ambient light events
ambient light events
window.addEventListener("deviceorientation", handleOrientation, true);
function handleOrientation(event) { var alpha = event.alpha; var beta = event.beta; var gamma = event.gamma;
// Do stuff with the new orientation data }
device orientation
device orientation
alpha
betagamma
getusermedia
var constraints = { audio: true };
var onSuccess = function(stream) { // do stuff with your media stream };
var onError = function(err) { console.log('The following error occurred: ' + err); }
navigator.getUserMedia(constraints, onSuccess, onError);
mediarecorder
var mediaRecorder = new MediaRecorder(stream);
record.onclick = function() { mediaRecorder.start(); }
stop.onclick = function() { mediaRecorder.stop(); }
mediaRecorder.ondataavailable = function(e) { var audio = document.createElement('audio'); audio.setAttribute('controls', ''); var audioURL = window.URL.createObjectURL(e.data); audio.src = audioURL; }
nfc
function ndefDiscoveredHandler(activity) { var data = activity.source.data; var tag = navigator.mozNfc.getNFCTag(data.sessionToken); console.log(tag instanceof MozNFCTag); // should print true }
var request = tag.readNDEF(); request.onsuccess = function() { var ndefRecords = request.result; // ndefRecords should be an array of MozNDEFRecord. };
nfc
navigator.mozNfc.onpeerready = function (evt) { var peer = navigator.mozNfc.getNFCPeer(evt.detail); console.log(peer instanceof MozNFCPeer); // should print true; };
var request = peer.sendNDEF(ndefRecords);
var request = peer.sendFile(blob);
Web speech API
๏ work in progress
๏ doing speech synthesis and recognition in javascript, client-side
privileged/certified api examples
๏ CAmERA
๏ FMradio
๏ bluetooth
๏ sms
๏ telephony
๏ Wifimanager
advanced communication
sometimes the web model can be a pain
๏ same origin security
๏ cors/systemxhr
๏ broadcast channels/message channels
๏ request response model
๏ web sockets
๏ webrtc
broadcast channels
// Connection to a broadcast channel var bc = new BroadcastChannel(“test_channel");
// Example of sending of a very simple message bc.postMessage("This is a test message.”);
// Exemple of a simple event handler that only // logs the event to the console bc.onmessage = function (e) { console.log(e); }
// Disconnect the channel bc.close()
channel messaging
var channel = new MessageChannel(); var ifr = document.querySelector('iframe'); var otherWindow = ifr.contentWindow; ifr.addEventListener("load", iframeLoaded, false); function iframeLoaded() { otherWindow.postMessage('Hello from the main page!', '*', [channel.port2]); }
channel.port1.onmessage = handleMessage; function handleMessage(e) { para.innerHTML = e.data; }
offline apps
no connection = no experience
offline is hard
The main problems are as follows:
๏ offline data storage
๏ offline asset storage
๏ detecting available network and reacting to it
offline data
this is not so bad:
๏ indexeddb, localstorage, websql
๏ (datastore api for firefox os)
๏ there’s something available in most browsers
๏ localforage library polyfills across browsers
offline apps/assets
offline app assets are a pain
๏ firefox os packaged apps are installed and available offline
๏ this doesn’t help the web at large
๏ we had app cache…
…this had promise...
CACHE MANIFEST # v1
CACHE: css/app.css index.html js/main.js
js/lib/require.js
...but was actually evil.
detecting network state
network state is also a pain
๏ Network information API is pretty unreliable
๏ you could check xhr responses, but this isn’t ideal
hello service workers!
This could be the answer…
service workers are coming
๏ proxy servers that sits between your app and the browser
๏ intercepting network requests and customising responses
๏ does similar things to app cache (plus a lot more)
๏ granular control over actions
register service worker
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw-test/sw.js', { scope: '/*' }).then(function(sw) { // registration worked console.log('Registration succeeded.'); }).catch(function() { // registration failed console.log('Registration failed.'); }); }
install service worker
this.addEventListener('install', function(event) { event.waitUntil( caches.create('v1').then(function(cache) { return cache.add( '/sw-test/', '/sw-test/index.html', '/sw-test/style.css', '/sw-test/app.js', '/sw-test/image-list.js', '/sw-test/star-wars-logo.jpg' // etc. ); }) ); });
custom request responses
this.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request).catch(function() { return event.default(); return caches.get('v1').then(function(cache) { cache.add(event.request); }); }).catch(function() { return caches.match('/sw-test/gallery/myLittleVader.jpg'); }) ); });
performance enhancers
performance enhancers
๏ web workers
๏ web audio api
๏ asm.js
๏ emscripten
web workers
web workers
๏ run scripts in a background thread
๏ don’t block the main thread execution
web audio api
web audio api
๏ precise control and manipulation of audio
๏ add effects to audio
๏ split and merge audio streams
๏ spatialise audio
๏ create audio visualisations
audiochannels
audiochannels api
๏ set different audio to play in different importance hierarchy
channels
๏ react to headphones being plugged in or unplugged
๏ more important audio can continue to play in the background, e.g.
music player audio
asm.js
asm.js
๏ a very efficient low-level subset of JS
๏ suitable for ahead-of-time optimizing compilation
๏ Unity3d now has asm.js/WebGL support
emscripten
emscripteN
๏ an LLVM to javascript compiler (well, asm.js, specifically)
๏ compile c++ (and others) into JS and run it on the web
๏ = “very fast shit” ™
๏ See emscripten.org
resources
๏ MDN: developer.mozilla.org/
๏ demos on github.com/mdn
๏ hacks blog: hacks.mozilla.org
๏ look up localforage - polyfill for indexeddb/websql/localstorage
๏ simplewebrtc.com - simple webrtc library
๏ emscripten.org - try quakejs.com
๏ asmjs.org
๏ mzl.la/openwebapps - give us your feedback on what the web
platform needs!
thanks for listening!!
slideshare.net/chrisdavidmills [email protected] // @chrisdavidmills