How to get a PWA to prompt you to install your website as an app
Progressive Web Applications
Getting Laravel up and running as an PWA application isn't tat hard. The challenge is rather what exactly do you want to do with said PWA? Here are some choices:
Have sexy icons
Send notifications
Install itself as an app
Do offline stuff
Online/offline sync
Since doing offline stuff is a bit of a rabbit hole, we're going to focus on install itself as an app. During the journey to get this working, we'll actually cover the entire lifecycle of getting a Laravel application up and running with PWA.
Note: Apple has bastardised PWAs in favour of their monopoly. If you need advice on getting this working on iPhone, see here:
Skipping some terminology and catchphrases, getting an PWA up and running means getting a Javascript service working running when a page is loaded, ie. your home page. You could of course to this on another page, but for most people the home page is it.
When we started this journey we found many articles referencing this repository: https://github.com/silviolleite/laravel-pwa
Most of this article's beginning is about reverse engineering that repo. The repo is great, but don't fool yourself. Actually the repo does very little, and the author is quite clear what is does in the readme. My opinion is you can skip a lot in the repo or install the repo and then roll your own, because mostly you would want control. Also, remember PWA programming involves a lot of Javascript so at the end of the day the repo just assist with the boilerplate and you'll be doing more Javascript than anything else.
Continuing, here is the most important bit of boilerplate you'll need to get started, namely the head section:
@include('pwa')
lang-php
What are we including? Here is it:
@php($config = config('pwa.manifest'))
<!-- Web Application Manifest -->
<link rel="manifest" href="{{ route('pwa.manifest') }}">
<!-- Chrome for Android theme color -->
<meta name="theme-color" content="{{ $config['theme_color'] }}">
<!-- Add to homescreen for Chrome on Android -->
<meta name="mobile-web-app-capable" content="{{ $config['display'] == 'standalone' ? 'yes' : 'no' }}">
<meta name="application-name" content="{{ $config['short_name'] }}">
<link rel="icon" sizes="{{ data_get(end($config['icons']), 'sizes') }}" href="{{ data_get(end($config['icons']), 'src') }}">
<!-- Add to homescreen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="{{ $config['display'] == 'standalone' ? 'yes' : 'no' }}">
<meta name="apple-mobile-web-app-status-bar-style" content="{{ $config['status_bar'] }}">
<meta name="apple-mobile-web-app-title" content="{{ $config['short_name'] }}">
<link rel="apple-touch-icon" href="{{ data_get(end($config['icons']), 'src') }}">
<link href="{{ $config['splash']['640x1136'] }}" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="{{ $config['splash']['750x1334'] }}" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="{{ $config['splash']['1242x2208'] }}" media="(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image" />
<link href="{{ $config['splash']['1125x2436'] }}" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image" />
<link href="{{ $config['splash']['828x1792'] }}" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="{{ $config['splash']['1242x2688'] }}" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image" />
<link href="{{ $config['splash']['1536x2048'] }}" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="{{ $config['splash']['1668x2224'] }}" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="{{ $config['splash']['1668x2388'] }}" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="{{ $config['splash']['2048x2732'] }}" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<!-- Tile for Win8 -->
<meta name="msapplication-TileColor" content="{{ $config['background_color'] }}">
<meta name="msapplication-TileImage" content="{{ data_get(end($config['icons']), 'src') }}">
<script type="text/javascript">
// Initialize the service worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/serviceworker.js', {
scope: '.'
}).then(function (registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
console.log("Online status: " + navigator.onLine);
}, function (err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
console.log("Online status: " + navigator.onLine);
});
}
</script>
lang-html
Note the extra bit of Javascript console output added:
We'll cover controller methods, because what we really want to do is get our hands dirty on some Javascript. So here is the key file you'll be spending time on:
// If you comment out this icon, on Chrome, Mac, Storm's icon will be used
'152x152' => [
'path' => '/images/icons/pwa/icon-152x152.png',
'purpose' => 'any'
],
lang-php