Transformace webové aplikace na progresivní webovou aplikaci (PWA) s push notifikacemi
Tento článek se zaměřuje na proces převodu standardní webové aplikace nebo webové stránky na PWA (Progressive Web App) s využitím push notifikací prostřednictvím služby Firebase Cloud Messaging.
V současné digitální éře je stále více webových aplikací transformováno na PWA, a to díky jejich pokročilým funkcím, jako je offline podpora, push notifikace a synchronizace na pozadí. Tyto vlastnosti PWA výrazně zvyšují uživatelský komfort a dojem, že se jedná o nativní aplikaci.
Jako příklad úspěšné transformace lze uvést společnosti Twitter a Amazon, které převedly své webové aplikace na PWA za účelem zvýšení interakce uživatelů.
Co je PWA?
PWA je kombinací tradiční webové aplikace (využívající HTML, CSS a JavaScript) a specifických funkcí nativních aplikací. Vaše webová aplikace funguje ve všech prohlížečích stejně, ale s moderními prohlížeči získává nativní vlastnosti. Díky tomu je výkonnější, škálovatelnější a umožňuje ukládání statických zdrojů do mezipaměti na straně klienta, což snižuje nároky na backend server.
Rozdíly mezi PWA a webovou aplikací
- Instalace: PWA lze instalovat jako nativní aplikaci.
- Progresivita: Funguje jako standardní webová aplikace, ale s pokročilými funkcemi.
- Nativní zážitek: Po instalaci se chová a vypadá jako nativní aplikace.
- Snadná dostupnost: Není nutné zadávat webové adresy při každé návštěvě. Aplikace se otevírá jedním klepnutím.
- Mezipaměť: PWA využívá pokročilé mechanismy pro ukládání do mezipaměti přímo na straně klienta, což webová aplikace nemá.
- Publikování: PWA lze publikovat v obchodech Google Play a App Store.
Převod aplikace na PWA zvýší její výkonnost a uživatelskou přívětivost.
Proč by podniky měly zvážit PWA?
Většina klientů nejprve žádá o vývoj webové aplikace a následně o nativní aplikace pro Android a iOS. To vyžaduje vývoj stejné funkcionality pro každou platformu samostatnými týmy, což zvyšuje náklady i dobu uvedení na trh.
PWA nabízí řešení pro klienty s omezeným rozpočtem nebo pro ty, kteří preferují rychlejší uvedení produktu na trh. Funkce PWA totiž mohou pokrýt většinu požadavků klientů, a pokud je potřeba distribuovat aplikaci v obchodech, lze PWA převést na nativní aplikaci pomocí TWA (Trusted Web Activity) pro Android.
V případech, kdy PWA nedokáže pokrýt všechny požadavky, lze samozřejmě vyvinout obě nativní aplikace, přičemž PWA může dočasně sloužit jako řešení dostupné v obchodu.
Například společnost Titan Eyeplus nejprve nasadila PWA v obchodě Play pomocí TWA a následně, po dokončení vývoje, svou skutečnou nativní aplikaci pro Android. Tím dosáhli jak rychlého uvedení na trh, tak i úspory nákladů.
Funkce PWA
PWA obohacuje webové aplikace o funkce známé z nativních aplikací, mezi které patří:
- Instalovatelnost: Instalace webové aplikace jako nativní.
- Mezipaměť: Možnost ukládání do mezipaměti pro offline podporu.
- Push notifikace: Zasílání push notifikací pro zvýšení interakce uživatelů.
- Geofencing: Upozornění při změně polohy zařízení.
- Platby: Možnost platby s uživatelským zážitkem jako u nativní aplikace.
Mezi další pokročilé funkce PWA patří:
- Zkratky: Rychlý přístup k URL adresám.
- Web Share API: Možnost sdílení dat s jinými aplikacemi.
- Badge API: Zobrazování počtu oznámení v PWA.
- Periodická synchronizace: Ukládání dat uživatele, dokud se nepřipojí k síti.
- Výběr kontaktů: Možnost výběru kontaktů z mobilu uživatele.
- File Picker: Přístup k souborům v lokálním systému.
Výhody PWA oproti nativním aplikacím
Ačkoliv nativní aplikace nabízí širší škálu funkcí, PWA má oproti nim několik výhod:
- Multiplatformnost: Běží na Androidu, iOS i počítačích.
- Snížení nákladů na vývoj: Nižší náklady na vývoj díky jednotné kódové základně.
- Snadné nasazení: Jednodušší a rychlejší implementace změn oproti nativním aplikacím.
- SEO: PWA je webová aplikace, která je dobře indexována vyhledávači.
- Bezpečnost: Běží pouze na HTTPS.
Nevýhody PWA oproti nativním aplikacím
- Omezená funkčnost: Omezený rozsah funkcí oproti nativním aplikacím.
- Podpora zařízení: Není zaručena podpora na všech zařízeních.
- Nízká značka: Menší viditelnost v porovnání s nativními aplikacemi v obchodech.
PWA lze publikovat v obchodu Play pomocí Android Trusted Web Activity (TWA), čímž zvýšíte její viditelnost.
Co je potřeba k převodu webové aplikace na PWA
Pro transformaci webové aplikace nebo webové stránky na PWA jsou nutné následující komponenty:
- Service Worker: Klíčový skript pro ukládání do mezipaměti, push notifikace a proxy pro požadavky.
- Manifest: Soubor s detailními informacemi o aplikaci, který se používá pro instalaci na domovskou obrazovku.
- Logo aplikace: Obrázek o rozměrech 512 x 512 pixelů pro ikonu aplikace. Je nutné vytvořit sadu obrázků s poměrem stran 1:1.
- Responzivní design: Aplikace musí být responzivní a fungovat na různých velikostech obrazovek.
Co je Service Worker?
Service Worker je skript na straně klienta, který funguje jako proxy mezi webovou aplikací a externími zdroji. Zajišťuje doručování push notifikací, ukládání do mezipaměti a běží nezávisle na hlavním JavaScriptu. Service Worker nemůže přímo přistupovat k DOM API, ale může využívat IndexedDB API, Fetch API a Cache Storage API. Pro komunikaci s hlavním vláknem používá zprávy.
Funkce zajišťované Service Workerem:
- Zachycování HTTP požadavků z domény.
- Příjem push notifikací ze serveru.
- Offline dostupnost aplikace.
Pro zajištění bezpečnosti a ochranu proti útokům man-in-the-middle musí běžet na HTTPS.
Co je soubor manifestu?
Soubor manifestu (manifest.json) obsahuje důležité detaily o PWA, které jsou nutné pro správnou funkčnost. Mezi tyto detaily patří:
- name: Název aplikace.
- short_name: Krátký název pro použití v omezeném prostoru.
- description: Popis aplikace.
- start_url: URL, na které se má aplikace spustit.
- icons: Sada obrázků pro různé účely (domovská obrazovka, úvodní obrazovka).
- background_color: Barva pozadí úvodní obrazovky.
- display: Určuje způsob zobrazení aplikace.
- theme_color: Barva motivu aplikace.
- scope: Rozsah URL, které spadají do PWA.
- shortcuts: Rychlé odkazy pro aplikaci.
Převod webové aplikace na PWA
Pro účely demonstrace jsem vytvořil strukturu složek webu etechblog.cz:
- index.html – domovská stránka
- články/
- index.html – stránka článků
- autoři/
- index.html – stránka autorů
- nástroje/
- index.html – stránka nástrojů
- nabídky/
- index.html – stránka s nabídkami
Pro převod existující webové stránky na PWA postupujte podle následujících kroků.
Vytvoření potřebných obrázků
Nejprve si připravte logo vaší aplikace a ořízněte ho do poměru 1:1 v pěti různých velikostech. Můžete využít online nástroj https://tools.crawlink.com/tools/pwa-icon-generator/.
Vytvoření souboru manifestu
Druhým krokem je vytvoření souboru manifest.json s detaily vaší webové aplikace. Následující kód je příklad souboru manifestu pro web etechblog.cz:
{ "name": "etechblog.cz", "short_name": "etechblog.cz", "description": "etechblog.cz 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": "etechblog.cz - Authors", "url": "/authors", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] }, { "name": "Tools", "short_name": "Tools", "description": "etechblog.cz - Tools", "url": "https://etechblog.cz.com/tools", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] }, { "name": "Deals", "short_name": "Deals", "description": "etechblog.cz - Deals", "url": "/deals", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] } ] }
Registrace Service Workeru
Vytvořte soubory `register-service-worker.js` a `service-worker.js` v kořenové složce projektu. První soubor se spouští v hlavním vlákně a má přístup k DOM API, zatímco druhý soubor je skript Service Workeru, který běží nezávisle a má omezenou životnost. Je aktivován při volání událostí a ukončen po dokončení procesu.
Zkontrolujte, zda je Service Worker registrován v hlavním JavaScriptovém souboru. Pokud ne, můžete zaregistrovat skript service-worker.js. Do souboru `register-service-worker.js` vložte následující kód:
if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/service-worker.js'); }); }
Do souboru `service-worker.js` vložte následující kód:
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); }) );*/ });
V tomto příkladu se nezaměřujeme na ukládání do mezipaměti pro offline podporu, ale pouze na samotný převod webové aplikace na PWA.
Přidejte odkaz na soubor manifestu a skript do sekce `head` vaší HTML stránky:
<link rel="manifest" href="https://etechblog.cz.com/manifest.json"> <script src="/register-service-worker.js"></script>
Po provedení těchto kroků obnovte stránku. Nyní by měla být vaše aplikace nainstalovatelná jako PWA v mobilním prohlížeči Chrome.
Instalovaná aplikace se zobrazí na domovské obrazovce.
Pokud používáte WordPress, zvažte použití existujícího pluginu pro převod na PWA. Pro frameworky Vue.js nebo React.js můžete postupovat podle výše uvedeného postupu nebo využít npm balíčky, které urychlí váš vývoj, protože tyto balíčky PWA již podporují ukládání do mezipaměti a offline režim.
Aktivace Push notifikací
Push notifikace jsou důležité pro zvýšení interakce uživatelů. Aktivace probíhá pomocí:
- Notification API: Konfigurace zobrazení notifikací pro uživatele.
- Push API: Příjem notifikací odeslaných ze serveru.
Prvním krokem je ověření podpory Notification API a získání uživatelského souhlasu se zobrazováním notifikací. Vložte následující kód do souboru 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); }); } };
Pokud vše proběhlo správně, měla by se vám zobrazit notifikace z aplikace. Hodnota ‚granted‘ v `Notification.permission` znamená, že uživatel povolil zobrazení notifikací. Hodnota ‚denied‘ by znamenala odmítnutí uživatelem.
Aktivace Firebase Cloud Messaging a vytvoření odběru
Pro odesílání notifikací ze serveru je potřeba získat jedinečný koncový bod (odběr) pro každého uživatele. K tomu využijeme Firebase Cloud Messaging.
Nejprve si vytvořte účet Firebase na https://firebase.google.com/ a vytvořte nový projekt. V tomto příkladu jej pojmenujeme „etechblog.cz“. V nastavení projektu vygenerujte klíče pro cloudové zprávy. Konkrétně se jedná o tyto tři klíče:
- projektový serverový klíč
- Webové push certifikáty soukromý klíč
- Webové push certifikáty veřejný klíč
Vložte následující kód do souboru `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();
Vložte následující kód do souboru `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) });
Po provedení těchto kroků je front-end připraven na push notifikace. Pomocí odběru můžete uživatelům zasílat notifikace, dokud si je neodhlásí.
Push notifikace z Node.js backendu
Pro usnadnění odesílání notifikací z Node.js backendu lze použít npm modul web-push. Následuje příklad, jak odeslat push notifikaci:
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 etechblog.cz-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 }); });
Push notifikace z PHP backendu
Pro PHP backend lze použít composer balíček web-push-php. Následuje příklad kódu pro odeslání push notifikace:
<?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 etechblog.cz-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) );
Závěr
Tento článek vám poskytl komplexní přehled o procesu transformace webové aplikace na PWA. Zdrojový kód je dostupný na GitHubu, a demo je dostupné na stránce. Push notifikace byly otestovány odesláním z backendu pomocí uvedených ukázkových kódů.