State of the Gap

State of the Gap

"PhoneGap is a polyfill, and the ultimate purpose of PhoneGap is to cease to exist" – Brian LeRoux, SPACELORD!1!! at Adobe, 2012.

Clearly PhoneGap, and Cordova are still required today, but when is it really needed? Did the web ever catch up? Do we always need to turn to a PhoneGap shell for all our solutions?

C8b387c489181844b3ffc704fadc0f14?s=128

Remy Sharp

May 19, 2016
Tweet

Transcript

  1. State of the gap Remy Sharp ☛ @rem

  2. PhoneGap: The polyfill

  3. PhoneGap is a polyfill, Brian LeRoux, SPACELORD!1!! Adobe, 2012. PhoneGap

    is a polyfill, and the ultimate purpose of PhoneGap PhoneGap is a polyfill, and the ultimate purpose of PhoneGap is to cease to exist. “
  4. Meanwhile, 7 years later…

  5. PhoneGap core

  6. Dialogs alert('OG dialogs ')

  7. <input type="file" accept="image/*;capture=camera"> Camera

  8. window.addEventListener('deviceorientation', handler) Accelerometer & Compass window.addEventListener('devicemotion', handler)

  9. var reader = new FileReader(); reader.onload = e => img.src

    = e.target.result; reader.readAsDataURL(this.files[0]); // this = input[type=file] Files
  10. function upload(blobOrFile) { var xhr = new XMLHttpRequest(); xhr.open('POST', '/server',

    true); xhr.onload = e => { /* show done…or something */ }; var progressBar = document.querySelector('progress'); xhr.upload.onprogress = e => { // track upload progress if (e.lengthComputable) { progressBar.value = (e.loaded / e.total) * 100; } }; xhr.send(blobOrFile); } upload(new Blob(['hello world'], {type: 'text/plain'})); File Transfer
  11. // now requires secure origin: HTTPS navigator.geolocation.getCurrentPosition(ok, fail); Geolocation

  12. function done(stream) { var url = window.URL.createObjectURL(stream); video.src = url;

    // starts to play video } navigator.getUserMedia({ video: true }, done, console.error); Media Capture
  13. navigator.getBattery()
 .then(b => b.level) .then(console.log); Battery

  14. navigator.connection.type; // wifi/cellular/none navigator.connection.ontypechange(handler) Network information

  15. navigator.vibrate(1000); Vibration

  16. None
  17. None
  18. PhoneGap vs. the web The ecosystem vs.

  19. Cross browser support Or…“the reason I left programming for the

    web”
  20. None
  21. plugins > browsers

  22. App Stores

  23. App Stores: 20% CPA

  24. 1. Visit app store 800 users 2. Find app 640

    users 3. Click install 512 users 4. Accept permissions 410 users 5. Download and wait 328 users 6. Use! 262 users left. 1000 users are interested in this app
  25. Full flow: 262 Direct install: 410 1000 users are interested

    in this app http://bit.ly/20pcent-dropoff
  26. What if…

  27. Progressive Web Apps

  28. 3X more time on site 40% high re-engagement 70% greater

    conversion from homescreen 3X lower data usage https://bit.ly/flipkart-study
  29. Security: TLS/HTTPS, permissions Performance: fast, responsive (in all senses) Availability:

    control of the network, homescreen, push notifications
  30. Requires manifest
 and service worker.

  31. If I add this app to my home screen, it

    will work when I open it.
  32. If I add this app to my home screen, it

    must work when I open it.
  33. None
  34. “Push notifications allowed us to bring one of the most

    compelling capabilities from our native app to our mobile site. We see a direct 20% click through rate from push notifications…” http://bit.ly/pwa-study-btr – Beyond the Rack
  35. 1. HTTPS 2. Service Worker 3. Manifest 4. Push notifications

  36. Service workers Event driven Uses promises and fetch API Register

    your service worker Then: install, fetch, activate, push
  37. <script> // progressively enhance if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js');

    } </script> http://bit.ly/sw-copy-paste
  38. const name = 'v1:static'; self.addEventListener('install', e => { // once

    the SW is installed, go ahead and fetch the // resources to make this work offline e.waitUntil( caches.open(name).then(cache => { return cache.addAll([ '/', // and other urls ]).then(() => self.skipWaiting()); }) ); }); http://bit.ly/sw-copy-paste
  39. // when the browser fetches a url, either response //

    with the cached object or go ahead and fetch // the actual url self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request).then( res => res || fetch(event.request) ) ); }); http://bit.ly/sw-copy-paste
  40. None
  41. None
  42. <link rel="manifest" href="/manifest.json">

  43. { "short_name": "My sweet app", "name": "This be the bees

    knees sweet app", "icons": [ { "src": "icon-4x.png", "sizes": "192x192", "type": "image/png" } ], "start_url": "/?utm_source=web_app_manifest", "display": "standalone", "orientation": "portrait", "background_color": "#ff0000", "theme_color": "#00ff00" } Preferred name property, appears on homescreen and on dynamic splash screen
  44. { "short_name": "My sweet app", "name": "This be the bees

    knees sweet app", "icons": [ { "src": "icon-4x.png", "sizes": "192x192", "type": "image/png" } ], "start_url": "/?utm_source=web_app_manifest", "display": "standalone", "orientation": "portrait", "background_color": "#ff0000", "theme_color": "#00ff00" } Array of icons available, at least include 192x192
  45. { "short_name": "My sweet app", "name": "This be the bees

    knees sweet app", "icons": [ { "src": "icon-4x.png", "sizes": "192x192", "type": "image/png" } ], "start_url": "/?utm_source=web_app_manifest", "display": "standalone", "orientation": "portrait", "background_color": "#ff0000", "theme_color": "#00ff00" } Optionally serve specific page to homescreen apps (and track)
  46. { "short_name": "My sweet app", "name": "This be the bees

    knees sweet app", "icons": [ { "src": "icon-4x.png", "sizes": "192x192", "type": "image/png" } ], "start_url": "/?utm_source=web_app_manifest", "display": "standalone", "orientation": "portrait", "background_color": "#ff0000", "theme_color": "#00ff00" } standalone, fullscreen, browser - how your appears on the device
  47. { "short_name": "My sweet app", "name": "This be the bees

    knees sweet app", "icons": [ { "src": "icon-4x.png", "sizes": "192x192", "type": "image/png" } ], "start_url": "/?utm_source=web_app_manifest", "display": "standalone", "orientation": "portrait", "background_color": "#ff0000", "theme_color": "#00ff00" } Games might choose to use landscape
  48. { "short_name": "My sweet app", "name": "This be the bees

    knees sweet app", "icons": [ { "src": "icon-4x.png", "sizes": "192x192", "type": "image/png" } ], "start_url": "/?utm_source=web_app_manifest", "display": "standalone", "orientation": "portrait", "background_color": "#ff0000", "theme_color": "#00ff00" } Colour used on dynamic splash page
  49. { "short_name": "My sweet app", "name": "This be the bees

    knees sweet app", "icons": [ { "src": "icon-4x.png", "sizes": "192x192", "type": "image/png" } ], "start_url": "/?utm_source=web_app_manifest", "display": "standalone", "orientation": "portrait", "background_color": "#ff0000", "theme_color": "#00ff00" } Colour used on Chrome tab
  50. { "short_name": "My sweet app", "name": "This be the bees

    knees sweet app", "icons": [ { "src": "icon-4x.png", "sizes": "192x192", "type": "image/png" } ], "start_url": "/?utm_source=web_app_manifest", "display": "standalone", "orientation": "portrait", "background_color": "#ff0000", "theme_color": "#00ff00" }
  51. None
  52. None
  53. Polymer: starter kit & elements WebRTC: PeerJS WebSockets: BinaryJs NodeJS

    Material Design
  54. Polymer: starter kit & elements WebRTC: PeerJS WebSockets: BinaryJs NodeJS

    Material Design UX:
  55. “We agree that there are no silver bullets, and the

    web isn’t the best tool for every job…
  56. “However, the web is not getting worse…

  57. “If the web doesn’t do something today it’s not because

    it can’t, or won’t…
  58. “but rather it is because we haven't gotten around to

    implementing that capability yet.
  59. “but rather it is because we haven't gotten around to

    implementing that capability yet.
  60. Thanks 
 (and thanks Brian)