I am Ada Rose from Samsung Internet Developer Relations I am here to talk to you about Web Apps. Can I have a quick show of hands:
I am here today to talk about web apps
Web Apps are websites which are so good your users will want to save them to their home screen.
They can be installed like apps.
Chrome will even produce an APK
Browsers will notify the users that they can be installed.
I am aiming this talk at everyone as good web app requires thoughts from both.
Building Web Apps
![]()
What the web can bring to Apps
Ada Rose Edwards - Samsung Research UK
@lady_ada_king, @samsunginternet
A quick example of a web app:
Increases Engagement
(Left) Poster showing how to download an events app; and (right) how it could have looked if they used a website instead.
– Peter Gasston (@stopsatgreen)
Cool Web Features
- Instant Engagement
- World Wide
- Safe for users
- Instant Deploy
- Access via URLs
- Accessibility
Cool App Features
- Works Offline
- Push Notifications
- Background Sync
- Icon on the Homescreen
- No URL Bar
- Not constrained to browser
How do you define an App?
It's in an App Store.
How do you define a Web Site?
It's in the browser.
How do you define a Web App?
Uhhh.....
![]()
Google Lighthouse
- Responsively Designed
- Performance
- Web App Manifest
- Triggers Browser Install Prompts
- Going Offline
- Push Notifications
- Progressive Enhancement
![]()
<meta name="MobileOptimized" content="width" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, minimal-ui" /> <meta name="HandheldFriendly" content="true" />
Web App Manifest
<meta name="apple-mobile-web-app-capable" content="yes"> <meta name="theme-color" content="#4E3F30"> <link rel="manifest" href="/static/manifest.json"> <link href="https://podle.ada.is/static/icon192.png" rel="icon" sizes="192x192" />
{ "name": "Podle", "icons": [ { "src": "/static/icon192.png", "sizes": "192x192", "type": "image/png" }, { "src": "/static/icon512.png", "sizes": "512x512", "type": "image/png" } ], "start_url": "/v7/", "display": "standalone", "background_color": "white", "theme_color": "#4E3F30" }
Triggering Browser Install Prompts
![]()
![]()
https://samsunginter.net/docs/ambient-badging.html
Registering a Service Worker
if ('serviceWorker' in navigator) { if (navigator.serviceWorker.controller) { // service worker already registered. return navigator.serviceWorker.ready; } else { // service worker not registered return navigator.serviceWorker.register('/sw.js', {scope: './'}) .then(() => navigator.serviceWorker.ready); } }
The browser will start your Service Worker when a request is made in your service worker’s scope
The browser may stop your worker at any point if it is not being used.
The service worker can intercept any fetch request made by the browser.
Intercepting Network requests
self.addEventListener('fetch', function(event) { const request = event.request; // Let videos go straight to the network if (request.url.match(/(\.mp4|\.webm|\.avi|\.wmv|\.m4v)$/i)) { return; } // Generate Response here if (request.url.match(/^https:\/\/ada.is\/static\//i)) { // doSomething, returns promise which resolves to a Response const responsePromise = doSomething(request); return event.respondWith(responsePromise); } });
- cache responses for speed
- cache responses to work offline
- create new responses
- precache static resources on app start
Push Notifications
4 steps to Push Notifications:
- Request permission
- Get endpoint & token, save to server
- On the server make an API call on the endpoint with your notification
- In the service worker listen for ‘push’ events and make a notification
Get permission
NB in Chrome and Samsung Internet you need to register on firebase cloud messaging and add your project’s id to your web app manifest.
gcm_sender_id": "103953800507"
// Has to occur with user input myButton.addEventListener('click', function () { navigator.serviceWorker.ready.then(function () { reg.pushManager.subscribe({ userVisibleOnly: true // declare we will use push for notifications }).then(function success(subscription) { // Tell user we are good to go storeSubscription(subscription); // see next slide }, function error() { // User may have declined or the browser or OS may have refused }); }); });
Save token to server
{ "endpoint": "http://example.com/some/uuid" }
In this case the url looks something like: https://android.googleapis.com/gcm/send/cz6YgbRXHAc:APA91bGWtm35_kAQsZEn_Ye…EVXj1MDXGulbtBWJYw4AGcIWXq7p5BjhFhnDhMQoqOHRzY9jI_OeOn_DQ5W_cYD5tCDDdjOD7d
function storeSubscription(subscription) { return fetch('/api/send-message', { method: 'POST', credentials: 'same-origin', headers: new Headers({ 'Content-Type': 'application/json', 'Accept': 'application/json' }), body: JSON.stringify(subscription) }) }
Using that token on the server:
Ideally make a post request to the endpoint.
BUT differing implementations make this a little awkward so I use:
https://github.com/web-push-libs/web-push
Making a notification
self.addEventListener('push', function (event) { const noti = self.registration.showNotification('Podcast updated', { icon: 'https://podle.ada.is/static/icon192.png', data: {title: 'Hello World'}, body: 'Lorem Ipsum' }); event.waitUntil(noti); }); self.addEventListener('notificationclick', function(event) { event.notification.close(); clients.openWindow('/'); });
The overarching theme here is: Inform the user, show them they have control.
When to ask for permission, give context clues. Don’t expect the user to trust you.
Say what you are going to use them for and make it clear where they can reduce their notifications.
Push notifications need to be timely. Don’t alert for something that does not need immediate attention.
Allow the user to not open your app.
A “yes or no” answer can be done in the notification itself!
![]()
https://slack.engineering/reducing-slacks-memory-footprint-4480fec7e8eb#.br9mtzz2r
Progressive Enhancement
Browser vendors have different priorities.
Future Web APIs coming soon to a browser near you
Web Share
Web Payment
Web Assembly
WebGL2
Some fun patterns it may be worth looking into:
Web App Patterns (Secret slide)
PRPL
Web App Shell Model
Headless Web