Konverter din webapp til PWA med push-varsler: En komplett guide

Konverter din nettapplikasjon til en PWA med push-varsler

I denne artikkelen skal vi se nærmere på hvordan du kan transformere en eksisterende webapplikasjon eller et nettsted til en Progressive Web App (PWA), komplett med push-varslingsfunksjonalitet ved hjelp av Firebase Cloud Messaging.

I dagens digitale landskap velger mange å konvertere sine nettapplikasjoner til PWA-er (Progressive Web Apps) på grunn av fordelene som tilbys. Disse inkluderer offline-tilgjengelighet, push-varsler og bakgrunnssynkronisering. PWA-funksjoner gir en mer nativ opplevelse for brukerne og gjør nettapplikasjonen mer engasjerende.

For å illustrere, har velkjente selskaper som Twitter og Amazon omgjort sine nettapplikasjoner til PWA-er for å øke brukerinteraksjonen.

Hva er en PWA?

En PWA kan defineres som: (Nettapplikasjon) + (utvalgte native funksjoner)

I bunn og grunn er en PWA den samme nettapplikasjonen din (HTML+CSS+JS) som fungerer som før i alle nettlesere. Men ved bruk av en moderne nettleser, får den tilgang til innebygde funksjoner. Dette resulterer i en kraftigere og mer skalerbar applikasjon, da ressurser kan forhåndshentes og lagres lokalt. Dette reduserer også antall forespørsler til backend-serveren.

Hvordan skiller PWA seg fra en tradisjonell webapplikasjon?

  • Installerbar: En PWA kan installeres som en native app på brukerens enhet.
  • Progressiv: Den fungerer som en vanlig nettapplikasjon, men med ekstra funksjonalitet.
  • Nativ App-Opplevelse: En installert PWA gir en sømløs brukeropplevelse som ligner på en native app.
  • Lett Tilgjengelig: Brukere trenger ikke lenger å skrive inn nettadresser hver gang. En installert PWA kan startes med et enkelt trykk.
  • Applikasjonsbufring: Med PWA kan vi lagre ressurser lokalt ved hjelp av kode på klientsiden, noe som ikke er mulig i en tradisjonell nettapplikasjon. Tidligere var man begrenset til HTTP-basert bufring i nettleseren.
  • Publisering i Appbutikker: PWA-er kan distribueres i både Google Play Store og iOS App Store.

Konvertering til PWA forbedrer applikasjonens kapasitet betydelig.

Hvorfor bør bedrifter vurdere PWA?

Mange kunder henvender seg i første omgang for å få utviklet en webapplikasjon, men etterspør også apper for Android og iOS. Dette krever at samme funksjonalitet bygges for hver plattform, noe som øker utviklingskostnadene og tiden det tar å lansere produktet.

Noen kunder har begrensede budsjetter, eller tid-til-marked er en prioritet.

PWA-funksjonalitet kan tilfredsstille de fleste kunders behov. Vi anbefaler da PWA og gir veiledning for hvordan PWA-en kan konverteres til en Android-app ved bruk av TWA (Trusted Web Activity) for distribusjon i Play Store.

Dersom kravene tilsier behov for funksjoner som ikke dekkes av PWA, kan det være nødvendig å utvikle separate applikasjoner for Android og iOS. Selv i slike tilfeller kan PWA distribueres i Play Store mens utviklingen av de native applikasjonene pågår.

Et eksempel er Titan Eyeplus, som startet med en PWA distribuert via TWA i Play Store, og senere lanserte en native Android-app. Dette ga dem en raskere time-to-market og kostnadsbesparelser.

PWA-funksjoner

PWA gir nettapplikasjoner native app-lignende funksjoner.

De viktigste funksjonene er:

  • Installerbar: Nettapplikasjonen installeres som en native app.
  • Bufring: Applikasjonsbufring er mulig, noe som gir offline-tilgjengelighet.
  • Push-varsler: Serveren kan sende push-varsler for å engasjere brukerne.
  • Geofencing: Applikasjonen kan motta varsler basert på endringer i enhetens plassering.
  • Betalingsforespørsler: Aktiver betalinger med en sømløs brukeropplevelse som i en native app.

Og mange flere funksjoner er under utvikling.

Andre funksjoner inkluderer:

  • Snarveier: Rask tilgang til spesifikke URL-er via manifestfilen.
  • Web Share API: Applikasjonen kan motta delte data fra andre applikasjoner.
  • Badge API: Vis antall varsler i den installerte PWA-en.
  • Periodic Background Sync API: Lagrer brukerdata til nettverkstilkoblingen gjenopprettes.
  • Kontaktvelger: Velg kontakter fra brukerens mobil.
  • Filvelger: Få tilgang til filer på det lokale systemet eller mobilenheten.

Fordeler med PWA over native applikasjoner

Selv om native apper ofte har bedre ytelse og flere funksjoner, har PWA-er sine fordeler:

  • PWA-er kjører på tvers av plattformer (Android, iOS, Desktop).
  • Det reduserer utviklingskostnader.
  • Enklere implementering av funksjoner sammenlignet med native apper.
  • Lett å finne da PWA-er er SEO-vennlige (nettsted).
  • Sikker da den kun fungerer over HTTPS.

Ulemper med PWA i forhold til native apper

  • Begrensede funksjoner sammenlignet med native apper.
  • PWA-funksjoner er ikke garantert å støtte alle enheter.
  • Lavere merkevarebygging, da den ikke er direkte tilgjengelig i appbutikker eller Play Butikken.

Du kan distribuere din PWA som en Android-app i Play Store ved hjelp av Android Trusted Web Activity (TWA). Dette vil styrke merkevarebyggingen.

Hva trenger du for å konvertere en nettapp til PWA?

For å konvertere en webapp eller et nettsted til PWA kreves følgende:

  • Service Worker: Kjernen i en PWA for hurtigbufring, push-varsler og som proxy for forespørsler.
  • Manifestfil: Inneholder detaljer om nettapplikasjonen som brukes for å installere den som en native app på startskjermen.
  • Applogo: Et høykvalitetsbilde (512 x 512 piksler) for appikonet, som er nødvendig for PWA-en på startskjermen, splash-skjermer etc. Vi trenger et sett med 1:1-forholdsbilder ved bruk av diverse verktøy.
  • Responsivt design: Appen må være responsiv og fungere på forskjellige skjermstørrelser.

Hva er en Service Worker?

En service worker (skript på klientsiden) fungerer som en mellommann mellom nettappen og omverdenen. Den leverer push-varsler og støtter hurtigbufring.

En service worker kjører uavhengig av hoved-javascriptet, og har derfor ikke tilgang til DOM API. Den har tilgang til IndexedDB API, Fetch API, og Cache Storage API. Den kan kommunisere med hovedtråden via meldinger.

Tjenester som leveres av en service worker:

  • Avskjærer HTTP-forespørsler fra opprinnelsesdomenet.
  • Mottar push-varsler fra serveren.
  • Gir offline-tilgjengelighet for applikasjonen.

Service worker kontrollerer applikasjonen og kan manipulere forespørsler, men den kjører uavhengig. Dette krever at opprinnelsesdomenet er aktivert med HTTPS for å unngå «man-in-the-middle»-angrep.

Hva er Manifest-filen?

En manifestfil (manifest.json) inneholder detaljer om PWA-en og gir informasjon til nettleseren:

  • name: Navnet på applikasjonen.
  • short_name: Et kort navn for applikasjonen (valgfritt). Hvis begge er gitt, vil nettleseren prioritere short_name.
  • description: Beskrivelse av applikasjonen.
  • start_url: Hjemmesiden til applikasjonen når PWA-en lanseres.
  • icons: Et sett med bilder for PWA-en, for bruk på startskjermen etc.
  • background_color: Angi bakgrunnsfargen på splash-skjermen.
  • display: Tilpass nettlesergrensesnittet i PWA-en.
  • theme_color: Tema farge for PWA-en.
  • scope: URL-området for PWA-en. Standard er plasseringen til manifestfilen.
  • shortcuts: Snarveier til funksjoner i PWA-en.

Konverter en nettapp til PWA

For demonstrasjonsformål har jeg laget en mappestruktur for et nettsted med statiske filer:

  • index.html – Hjemmeside
  • artikler/
    • index.html – Artikkelside
  • forfattere/
    • index.html – Forfatterside
  • verktøy/
    • index.html – Verktøyside
  • tilbud/
    • index.html – Tilbudsside

Hvis du allerede har et nettsted eller en webapp, kan du prøve å konvertere det til PWA ved å følge trinnene nedenfor.

Lag nødvendige bilder for PWA

Først beskjærer du applogoen din i forholdet 1:1 i fem forskjellige størrelser. Jeg har brukt https://tools.crawlink.com/tools/pwa-icon-generator/ for å få forskjellige bildestørrelser raskt. Du kan bruke samme verktøy.

Opprett en manifestfil

Deretter oppretter du en manifest.json-fil med appens detaljer. Her er et eksempel for nettstedet:

{
	"name": "tipsbilk.net",
	"short_name": "tipsbilk.net",
	"description": "tipsbilk.net produces high-quality technology & finance articles, makes tools, and APIs to help businesses and people grow.",
	"start_url": "/",
	"icons": [{
		"src": "assets/icon/icon-128x128.png",
		"sizes": "128x128",
		"type": "image/png"
	}, {
		"src": "assets/icon/icon-152x152.png",
		"sizes": "152x152",
		"type": "image/png"
	}, {
		"src": "assets/icon/icon-192x192.png",
		"sizes": "192x192",
		"type": "image/png"
	}, {
		"src": "assets/icon/icon-384x384.png",
		"sizes": "384x384",
		"type": "image/png"
	}, {
		"src": "assets/icon/icon-512x512.png",
		"sizes": "512x512",
		"type": "image/png"
	}],
	"background_color": "#EDF2F4",
	"display": "standalone",
	"theme_color": "#B20422",
	"scope": "/",
	"shortcuts": [{
			"name": "Articles",
			"short_name": "Articles",
			"description": "1595 articles on Security, Sysadmin, Digital Marketing, Cloud Computing, Development, and many other topics.",
			"url": "https://geekflare.com/articles",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		},
		{
			"name": "Authors",
			"short_name": "Authors",
			"description": "tipsbilk.net - Authors",
			"url": "/authors",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		},
		{
			"name": "Tools",
			"short_name": "Tools",
			"description": "tipsbilk.net - Tools",
			"url": "https://tipsbilk.net.com/tools",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		},
		{
			"name": "Deals",
			"short_name": "Deals",
			"description": "tipsbilk.net - Deals",
			"url": "/deals",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		}
	]
}

Registrer Service Worker

Opprett to skriptfiler: register-service-worker.js og service-worker.js i rotmappen.

register-service-worker.js er et javascript-fil som kjøres i hovedtråden og har tilgang til DOM API, mens service-worker.js kjører uavhengig av hovedtråden. Den har kort levetid og kjøres hver gang hendelser utløser service-worker.

I javascript-filen i hovedtråden sjekker du om service-worker er registrert. Hvis ikke, registrerer du service worker-skriptet (service-worker.js).

Lim inn følgende kode i register-service-worker.js:

if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
        navigator.serviceWorker.register('/service-worker.js');
    });
}

Lim inn følgende kode i service-worker.js:

self.addEventListener('install', (event) => { // event when service worker install
    console.log( 'install', event);
    self.skipWaiting();
});

self.addEventListener('activate', (event) => { // event when service worker activated
    console.log('activate', event);
    return self.clients.claim();
});

self.addEventListener('fetch', function(event) { // HTTP request interceptor
    event.respondWith(fetch(event.request)); // send all http request without any cache logic
    /*event.respondWith(
        caches.match(event.request).then(function(response) {
            return response || fetch(event. request);
        })
    );*/ // cache new request. if already in cache serves with the cache.
});

Vi fokuserer ikke på hvordan man aktiverer hurtigbufring for offline-støtte i denne artikkelen, men konsentrerer oss om konvertering av nettapp til PWA.

Legg til manifestfilen og skriptene i <head>-taggen på HTML-siden din:

<link rel="manifest" href="https://tipsbilk.net.com/manifest.json">
<script src="/register-service-worker.js"></script>

Oppdater siden etter at du har lagt til koden. Nå kan du installere applikasjonen din via mobil Chrome, som vist nedenfor.

Applikasjonen legges til på startskjermen.

Hvis du bruker WordPress, bør du vurdere å bruke et eksisterende plugin for PWA-konvertering. For VueJS eller ReactJS kan du bruke den ovennevnte metoden eller eksisterende npm-moduler for å fremskynde utviklingen, da disse gjerne inkluderer offline-støtte og bufring.

Aktiver push-varsler

Web-push-varsler sendes til nettleseren for å øke brukerengasjement. Du kan aktivere det ved å bruke:

  • Notification API: For å konfigurere hvordan push-varslene vises.
  • Push API: For å motta varslingsmeldinger fra serveren.

Det første trinnet er å sjekke om Notification API støttes og å be om tillatelse fra brukeren. Lim inn følgende kode i register-service-worker.js:

if ('Notification' in window && Notification.permission != 'granted') {
    console.log('Ask user permission')
    Notification.requestPermission(status => {  
        console.log('Status:'+status)
        displayNotification('Notification Enabled');
    });
}


const displayNotification = notificationTitle => {
    console.log('display notification')
    if (Notification.permission == 'granted') {
        navigator.serviceWorker.getRegistration().then(reg => {
            console.log(reg)
            const options = {
                    body: 'Thanks for allowing push notification !',
                    icon:  '/assets/icons/icon-512x512.png',
                    vibrate: [100, 50, 100],
                    data: {
                      dateOfArrival: Date.now(),
                      primaryKey: 0
                    }
                  };
    
            reg.showNotification(notificationTitle, options);
        });
    }
};

Dersom alt går bra, skal du motta et varsel fra applikasjonen:

«Notification» i vinduet indikerer at Notification API støttes i nettleseren. Notification.permission viser om brukeren har gitt tillatelse til å vise varsler. Verdien vil være «granted» om brukeren har tillatt, eller «denied» om brukeren har avvist.

Aktiver Firebase Cloud Messaging og opprett abonnement

Nå starter den faktiske jobben. For å sende varsler fra serveren til brukerne trenger vi et unikt endepunkt/abonnement for hver bruker. Dette oppnår vi med Firebase Cloud Messaging.

Start med å opprette en Firebase-konto på https://firebase.google.com/, og trykk på «Kom i gang».

  • Opprett et nytt prosjekt med et navn og trykk fortsett.
  • I neste trinn er Google Analytics aktivert som standard. Du kan slå av den og trykke fortsett. Du kan aktivere den senere i Firebase konsollen om du ønsker det.

Når prosjektet er opprettet skal det se slik ut:

Gå til prosjektinnstillinger og trykk på skymeldinger og generer nøkler.

Du vil nå ha 3 nøkler:

  • Prosjektserver-nøkkel
  • Web-push-sertifikater privat nøkkel
  • Web-push-sertifikater offentlig nøkkel

Lim inn følgende kode i register-service-worker.js:

const updateSubscriptionOnYourServer = subscription => {
    console.log('Write your ajax code here to save the user subscription in your DB', subscription);
    // write your own ajax request method using fetch, jquery, axios to save the subscription in your server for later use.
};

const subscribeUser = async () => {
    const swRegistration = await navigator.serviceWorker.getRegistration();
    const applicationServerPublicKey = 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY'; // paste your webpush certificate public key
    const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
    swRegistration.pushManager.subscribe({
      userVisibleOnly: true,
      applicationServerKey
    })
    .then((subscription) => {
        console.log('User is subscribed newly:', subscription);
        updateSubscriptionOnServer(subscription);
    })
    .catch((err) => {
        if (Notification.permission === 'denied') {
          console.warn('Permission for notifications was denied')
        } else {
          console.error('Failed to subscribe the user: ', err)
        }
    });
};
const urlB64ToUint8Array = (base64String) => {
    const padding = '='.repeat((4 - base64String.length % 4) % 4)
    const base64 = (base64String + padding)
        .replace(/-/g, '+')
        .replace(/_/g, '/')

    const rawData = window.atob(base64);
    const outputArray = new Uint8Array(rawData.length);

    for (let i = 0; i < rawData.length; ++i) {
        outputArray[i] = rawData.charCodeAt(i);
    }
    return outputArray;
};

const checkSubscription = async () => {
    const swRegistration = await navigator.serviceWorker.getRegistration();
    swRegistration.pushManager.getSubscription()
    .then(subscription => {
        if (!!subscription) {
            console.log('User IS Already subscribed.');
            updateSubscriptionOnYourServer(subscription);
        } else {
            console.log('User is NOT subscribed. Subscribe user newly');
            subscribeUser();
        }
    });
};

checkSubscription();

Lim inn følgende kode i service-worker.js.

self.addEventListener('push', (event) => {
  const json = JSON.parse(event.data.text())
  console.log('Push Data', event.data.text())
  self.registration.showNotification(json.header, json.options)
});

Nå er alt klart i front-end. Ved bruk av abonnementet kan du sende push-varsler til brukerne når du ønsker, med mindre de har blokkert for push-tjenestene.

Push fra node.js backend

Du kan bruke web-push npm modul for å forenkle prosessen.

Eksempel på kode for å sende push-varsler fra en nodeJS-server:

const webPush = require('web-push');
    // pushSubscription is nothing but subscription that you sent from your front-end to save it in DB
    const pushSubscription = {"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/gAAAAABh2…E0mTFsHtUqaye8UCoLBq8sHCgo2IC7UaafhjGmVCG_SCdhZ9Z88uGj-uwMcg","keys":{"auth":"qX6AMD5JWbu41cFWE3Lk8w","p256dh":"BLxHw0IMtBMzOHnXgPxxMgSYXxwzJPxpgR8KmAbMMe1-eOudcIcUTVw0QvrC5gWOhZs-yzDa4yKooqSnM3rnx7Y"}};
    //your web certificates public-key
    const vapidPublicKey = 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY';
    //your web certificates private-key
    const vapidPrivateKey = 'web-certificate private key';

    var payload = JSON.stringify({
      "options": {
        "body": "PWA push notification testing fom backend",
        "badge": "/assets/icon/icon-152x152.png",
        "icon": "/assets/icon/icon-152x152.png",
        "vibrate": [100, 50, 100],
        "data": {
          "id": "458",
        },
        "actions": [{
          "action": "view",
          "title": "View"
        }, {
          "action": "close",
          "title": "Close"
        }]
      },
      "header": "Notification from tipsbilk.net-PWA Demo"
    });

    var options = {
      vapidDetails: {
        subject: 'mailto:[email protected]',
        publicKey: vapidPublicKey,
        privateKey: vapidPrivateKey
      },
      TTL: 60
    };

    webPush.sendNotification(
      pushSubscription,
      payload,
      options
    ).then(data => {
      return res.json({status : true, message : 'Notification sent'});
    }).catch(err => {
      return res.json({status : false, message : err });
    });

Koden over vil sende en push melding til abonnementet. Push-hendelsen i service-workeren vil bli utløst.

Push fra PHP backend

For PHP-backend kan du bruke web-push-php composerpakke. Her er et eksempel på hvordan du kan sende push-varsler:

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

require __DIR__.'/../vendor/autoload.php';
use MinishlinkWebPushWebPush;
use MinishlinkWebPushSubscription;

// subscription stored in DB
$subsrciptionJson = '{"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/gAAAAABh2…E0mTFsHtUqaye8UCoLBq8sHCgo2IC7UaafhjGmVCG_SCdhZ9Z88uGj-uwMcg","keys":{"auth":"qX6AMD5JWbu41cFWE3Lk8w","p256dh":"BLxHw0IMtBMzOHnXgPxxMgSYXxwzJPxpgR8KmAbMMe1-eOudcIcUTVw0QvrC5gWOhZs-yzDa4yKooqSnM3rnx7Y"}}';
$payloadData = array (
'options' =>  array (
                'body' => 'PWA push notification testing fom backend',
                'badge' => '/assets/icon/icon-152x152.png',
                'icon' => '/assets/icon/icon-152x152.png',
                'vibrate' => 
                array (
                  0 => 100,
                  1 => 50,
                  2 => 100,
                ),
                'data' => 
                array (
                  'id' => '458',
                ),
                'actions' => 
                array (
                  0 => 
                  array (
                    'action' => 'view',
                    'title' => 'View',
                  ),
                  1 => 
                  array (
                    'action' => 'close',
                    'title' => 'Close',
                  ),
                ),
),
'header' => 'Notification from tipsbilk.net-PWA Demo',
);

// auth
$auth = [
    'GCM' => 'your project private-key', // deprecated and optional, it's here only for compatibility reasons
    'VAPID' => [
        'subject' => 'mailto:[email protected]', // can be a mailto: or your website address
        'publicKey' => 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY', // (recommended) uncompressed public key P-256 encoded in Base64-URL
        'privateKey' => 'your web-certificate private-key', // (recommended) in fact the secret multiplier of the private key encoded in Base64-URL
    ],
];

$webPush = new WebPush($auth);

$subsrciptionData = json_decode($subsrciptionJson,true);


// webpush 6.0
$webPush->sendOneNotification(
  Subscription::create($subsrciptionData),
  json_encode($payloadData) // optional (defaults null)
);

Konklusjon

Jeg håper dette gir deg et overblikk over hvordan du kan konvertere dine nettapplikasjoner til PWA. Du kan finne kildekoden til denne artikkelen her og demoen her. Jeg har testet push-varslingen ved å sende den fra backend, ved bruk av eksempelkoden.