Hur man konverterar WebApp som PWA med Push Notification

By rik

Förvandla din webbplats till en PWA med push-notiser

I den här artikeln undersöker vi hur man konverterar en vanlig webbapplikation eller webbplats till en Progressiv Webbapp (PWA) som har stöd för push-notiser med hjälp av Firebase Cloud Messaging.

I dagens digitala landskap väljer många att omvandla sina webbapplikationer till PWA. Detta beror på de många fördelar det medför, såsom offline-funktionalitet, möjligheten att skicka push-notiser och synkronisering i bakgrunden. Dessa funktioner gör att en webbapp får ett mer nativt app-liknande beteende, vilket leder till en förbättrad användarupplevelse.

Etablerade företag som Twitter och Amazon har redan sett värdet i att konvertera sina webbaserade tjänster till PWA för att öka användarinteraktionen.

Vad är egentligen en PWA?

En PWA kan beskrivas som en: (webbapp) + (vissa nativa app-egenskaper)

Grundläggande utgörs en PWA av samma komponenter som en traditionell webbapplikation (HTML, CSS och JavaScript). Den fungerar alltså precis som din vanliga webbplats i alla webbläsare. Det som skiljer den åt är att den i moderna webbläsare kan dra nytta av inbyggda funktioner. Denna kombination av webbteknik och tillgång till API:er för mobilfunktionalitet gör den mer kraftfull och skalbar. Genom att förhandsladda och lagra resurser i klienten minskar antalet anrop till din backend-server.

Skillnaden mellan en PWA och en vanlig Webbapp

  • Installationsbar: En PWA kan installeras som en separat applikation, likt en native app.
  • Progressiv: Den fungerar i grunden som en vanlig webbapp, men med tillägg av vissa integrerade funktioner.
  • Nativ App-känsla: När den väl är installerad kan användaren navigera och interagera med appen som om det vore en native app.
  • Lättillgänglig: Till skillnad från traditionella webbplatser behöver användarna inte mata in en webbadress varje gång. En PWA kan öppnas med ett enkelt klick efter installation.
  • Applikationscache: Till skillnad från traditionella webbappar som bara har tillgång till webbläsarens HTTP-cache, kan en PWA cacha data via kod i klienten.
  • Publicering i Appbutiker: PWA:er kan distribueras i både Google Play Store och iOS App Store.

Att konvertera din webbapp till en PWA är ett steg i rätt riktning för att förbättra funktionalitet och användarupplevelse.

Varför företag bör överväga PWA

Ofta kontaktar kunder utvecklare för att först få en webbapp utvecklad, och sedan begär de en Android- och iOS-version av samma app. Detta innebär att separata team behöver återskapa samma funktioner i native appar, vilket resulterar i ökade utvecklingskostnader och en längre lanseringstid.

Vissa kunder har dock en stram budget, eller så är snabb lanseringstid av största vikt. PWA:er kan i många fall uppfylla kundernas krav med sina tillgängliga funktioner. Därför föreslår vi ofta PWA som en första lösning och ger information om möjligheten att publicera PWA:n i Google Play Store som en Android-app via TWA (Trusted Web Activity) om det är nödvändigt.

Om kundens behov kräver specifika native app-funktioner som en PWA inte kan erbjuda, kan en native app utvecklas. Även i det fallet kan PWA användas som en tillfällig lösning i Play Store medan utvecklingen av den native appen pågår.

Ett exempel på detta är Titan Eyeplus. De lanserade först en PWA i Play Store med hjälp av TWA. När den riktiga Android-appen var klar, ersatte den PWA:n. Detta gjorde det möjligt för dem att snabbt lansera en fungerande version och samtidigt kontrollera utvecklingskostnaderna.

PWA-funktioner

PWA ger webbapplikationer funktioner som liknar native appars.

De viktigaste funktionerna inkluderar:

  • Installationsbar: En webbapplikation som kan installeras direkt på enheten.
  • Caching: Möjligheten till applikationscache ger stöd för offline-läge.
  • Push-meddelanden: Möjligheten att skicka push-meddelanden från servern för att hålla användarna engagerade.
  • Geofencing: Applikationen kan reagera på förändringar i enhetens position.
  • Betalningsförfrågningar: Aktivera betalningar i applikationen med en användarupplevelse i klass med native appar.

Ytterligare funktioner är under utveckling och kommer att finnas tillgängliga inom kort.

Andra funktioner:

  • Genvägar: Snabbåtkomstlänkar som definieras i manifestfilen.
  • Web Share API: Tillåter applikationen att ta emot data delad från andra applikationer.
  • Badge API: Visar antalet aviseringar i den installerade PWA:n.
  • Periodic Background Sync API: Sparar användardata lokalt tills en nätverksanslutning är tillgänglig.
  • Kontaktväljare: Tillåter användare att välja kontakter från sin mobil.
  • Filväljare: Ger tillgång till filer i det lokala filsystemet eller mobilen.

Fördelar med PWA jämfört med Native Applikationer

Native appar är ofta mer effektiva och har fler tillgängliga funktioner. Men PWA har fortfarande vissa fördelar:

  • PWA fungerar på flera plattformar, inklusive Android, iOS och stationära datorer.
  • PWA minskar utvecklingskostnaderna.
  • Funktionsdistribution är enklare jämfört med native appar.
  • PWA (webbplatsen) är SEO-vänlig, vilket gör den mer lättillgänglig.
  • Säkerhet garanteras eftersom PWA enbart använder HTTPS.

Nackdelar med PWA jämfört med native appar

  • Färre funktioner jämfört med en native app.
  • Stödet för PWA-funktioner garanteras inte på alla enheter.
  • PWA har lägre varumärkesexponering eftersom den inte finns tillgänglig i appbutiker direkt.

Du kan publicera din PWA som en Android-app i Play Store genom att använda Android Trusted Web Activity (TWA). Detta bidrar till att öka varumärkeskännedomen.

Nödvändiga komponenter för att konvertera en webbapp till en PWA

För att konvertera en webbapplikation eller webbplats till en PWA behövs följande komponenter:

  • Service Worker: Kärnan i alla PWA:er. Ansvarar för caching, push-meddelanden och hantering av förfrågningar.
  • Manifestfil: Innehåller information om din webbapplikation och används vid installation av appen på hemskärmen.
  • Applogotyp: Högkvalitativ bild (512 x 512 px) som används som appikon på hemskärmen och startskärmen, samt för andra ändamål. Bilder i förhållandet 1:1 rekommenderas.
  • Responsiv design: Webbappen ska anpassas till olika skärmstorlekar för optimal användning.

Vad är en Service Worker?

En service worker är ett skript på klientsidan som fungerar som en proxy mellan din webbapplikation och omvärlden. Den hanterar push-meddelanden och stöder cachelagring.

Service workers körs separat från JavaScript på huvudsidan och har därför inte direkt tillgång till DOM API. Istället har den tillgång till API:er som IndexedDB API, Fetch API, och Cache Storage API. Den kan kommunicera med huvudtråden genom meddelanden.

Tjänster som tillhandahålls av service workers:

  • Hantering av HTTP-förfrågningar från din domän.
  • Mottagning av push-meddelanden från servern.
  • Möjliggör offline-användning av applikationen.

Service worker kontrollerar din applikation och kan bearbeta förfrågningar, men den körs oberoende. Därför är det viktigt att domänen har stöd för HTTPS för att undvika man-in-the-middle-attacker.

Vad är en Manifest-fil?

En manifestfil (manifest.json) innehåller viktig information om PWA:n som webbläsaren behöver.

  • name: Applikationens namn.
  • short_name: Ett kortare namn för applikationen som används när utrymmet är begränsat.
  • Om både name och short_name anges kommer webbläsaren att använda short_name.
  • description: En beskrivning av applikationens funktion.
  • start_url: Applikationens startsida när PWA:n startas.
  • icons: En uppsättning bilder som används som ikoner för PWA på hemskärmen.
  • background_color: Bakgrundsfärgen för startskärmen i applikationen.
  • display: Anpassar webbläsargränssnittet för PWA:n.
  • theme_color: Applikationens temafärg.
  • scope: URL-området för applikationen, som normalt är platsen där manifestfilen finns.
  • shortcuts: Snabblänkar för applikationen.

Konvertera en webbapp till en PWA

I demonstrationssyfte har jag skapat en mappstruktur för en webbplats, adminvista.com, som innehåller statiska filer:

  • index.html – startsida
  • artiklar/
    • index.html – artikelsida
  • författare/
    • index.html – författarsida
  • verktyg/
    • index.html – verktygssida
  • erbjudanden/
    • index.html – erbjudandesida

Om du redan har en befintlig webbplats eller webbapp, kan du följa stegen nedan för att konvertera den till en PWA.

Skapa nödvändiga bilder för PWA

Börja med att beskära din applogotyp till 1:1 i fem olika storlekar. Jag har använt verktyget https://tools.crawlink.com/tools/pwa-icon-generator/ för att snabbt skapa olika bildstorlekar. Du kan använda samma verktyg eller något annat liknande.

Skapa en manifestfil

Skapa en manifest.json-fil för din applikation med relevant information. Som exempel har jag skapat en manifestfil för webbplatsen adminvista.com:

{
	"name": "adminvista.com",
	"short_name": "adminvista.com",
	"description": "adminvista.com 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": "adminvista.com - Authors",
			"url": "/authors",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		},
		{
			"name": "Tools",
			"short_name": "Tools",
			"description": "adminvista.com - Tools",
			"url": "https://adminvista.com.com/tools",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		},
		{
			"name": "Deals",
			"short_name": "Deals",
			"description": "adminvista.com - Deals",
			"url": "/deals",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		}
	]
}

Registrera Service Worker

Skapa filerna register-service-worker.js och service-worker.js i rotmappen för webbplatsen.

register-service-worker.js körs i huvudtråden och har tillgång till DOM API, medan service-worker.js körs separat och kan inte manipulera DOM direkt. Service worker aktiveras vid händelser och avslutas när uppgiften är klar.

Genom att kontrollera JavaScript-koden i huvudtråden kan du avgöra om en service worker är registrerad. Om ingen finns registrerad kan du registrera service worker-skriptet (service-worker.js).

Klistra in följande kod i register-service-worker.js:

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

Klistra in följande kod i service-worker.js:

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

self.addEventListener('activate', (event) => {
    console.log('activate', event);
    return self.clients.claim();
});

self.addEventListener('fetch', function(event) {
    event.respondWith(fetch(event.request));
    /*event.respondWith(
        caches.match(event.request).then(function(response) {
            return response || fetch(event. request);
        })
    );*/
});

Vi fokuserar inte på att aktivera cache för offlinesupport i denna artikel, utan på att konvertera webbappar till PWA.

Lägg till referenser till manifestfilen och JavaScript-skripten i <head>-elementet på din HTML-sida:

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

Uppdatera sidan när du har gjort ändringarna. Nu kan du installera din applikation som en PWA på Chrome på mobilen. Appen läggs till på hemskärmen.

Om du använder WordPress, överväg att använda ett tillgängligt PWA-plugin. För Vue.js eller React.js kan du använda ovanstående metod eller använda PWA npm-moduler för snabbare utveckling. Dessa npm-moduler är ofta redan konfigurerade med stöd för offline-cache och annat.

Aktivera Push-meddelanden

Webb-push-meddelanden kan användas för att öka användarinteraktionen med din applikation. Du kan aktivera dem med hjälp av följande API:er:

  • Notification API: Används för att definiera hur push-meddelanden ska presenteras för användaren.
  • Push API: Används för att ta emot aviseringsmeddelanden som skickas från servern till webbläsaren.

Första steget är att kontrollera Notification API:et och be om användarens tillåtelse att visa notiser. För att göra det, lägg till nedanstående kod i din 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);
        });
    }
};

Om allt går som det ska kommer ett meddelande att visas från appen.

Koden 'Notification' in window indikerar att Notification API stöds i webbläsaren. Notification.permission visar om användaren har gett tillåtelse. Värdet blir ”granted” om användaren har gett tillåtelse eller ”denied” om användaren har nekat tillåtelse.

Aktivera Firebase Cloud Messaging och Skapa Prenumeration

För att skicka meddelanden från din server till användarna behövs en unik slutpunkt/prenumeration för varje användare. Här används Firebase Cloud Messaging.

Första steget är att skapa ett Firebase-konto via https://firebase.google.com/ och klicka på ”Kom igång”.

  1. Skapa ett nytt projekt med ett valfritt namn (jag valde adminvista.com) och klicka på ”Fortsätt”.
  2. I nästa steg är Google Analytics aktiverat som standard, men det kan avaktiveras. Klicka på ”Fortsätt”. Det kan aktiveras igen senare i Firebase-konsolen.
  3. När projektet är skapat kommer det att visas som nedan:

Gå sedan till projektinställningarna och klicka på ”Molnmeddelanden” för att generera nycklar.

Dessa steg genererar tre nycklar:

  • Projektservernyckel
  • Webb-push certifikat privat nyckel
  • Webb-push certifikat offentlig nyckel

Klistra in följande kodavsnitt 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();

Lägg till följande kodavsnitt 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)
});

Nu är all frontend-kod på plats. Med hjälp av prenumerationen kan du nu skicka push-meddelanden till användare när du vill, förutsatt att användaren inte har nekat push-tjänsten.

Push från Node.js Backend

Du kan använda web-push npm-modulen för att förenkla processen.

Exempel på kod för att skicka push-meddelanden från 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 adminvista.com-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 });
    });

Denna kod skickar ett push-meddelande till den angivna prenumerationen. Push-händelsen i service-workern kommer att utlösas.

Push från PHP Backend

För PHP-backend kan du använda web-push-php kompositörspaketet. Nedan finns ett exempel på hur du skickar push-meddelanden.

<?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 adminvista.com-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_LW9ia0lMr68TsTLKS3Ucd