Jak převést WebApp jako PWA pomocí Push Notification

V tomto článku se podíváme na to, jak převést webovou aplikaci nebo web na PWA s oznámením Push pomocí služby Firebase Cloud Messaging.

V moderním světě se většina webových aplikací převádí na PWA (Progressive Web App), protože poskytuje funkce, jako je podpora offline, oznámení push, synchronizace na pozadí. Funkce PWA dělají z naší webové aplikace spíše nativní aplikaci a poskytují bohatý uživatelský zážitek.

Například skvělé společnosti jako Twitter a Amazon převedly svou webovou aplikaci na PWA pro větší zapojení uživatelů.

Co je PWA?

PWA = (webová aplikace) + (některé funkce nativní aplikace)

PWA je vaše stejná webová aplikace (HTML+CSS+JS). Funguje stejně jako vaše webová aplikace ve všech prohlížečích jako dříve. Ale může mít nativní funkce, když se váš web načte v moderním prohlížeči. Díky tomu je vaše webová aplikace výkonnější než dříve a také je škálovatelnější, protože můžeme předem načítat a ukládat prostředky do mezipaměti na frontendu, což snižuje požadavky na váš backend server.

Jak se PWA liší od Web App

  • Instalovatelné: Vaši webovou aplikaci lze nainstalovat jako nativní aplikaci
  • Progresivní: Funguje stejně jako vaše webová aplikace, ale s některými nativními funkcemi
  • Nativní aplikace: Po instalaci může uživatel používat a procházet webovou aplikaci jako nativní.
  • Snadno dostupné: Na rozdíl od naší webové aplikace nemusí naši uživatelé při každé návštěvě zadávat webové adresy. Po instalaci jej lze otevřít jediným klepnutím.
  • Ukládání aplikací do mezipaměti: Před PWA byl jediným mechanismem mezipaměti, se kterým naše webová aplikace implementovala, použití mezipaměti HTTP, která je dostupná pouze prohlížeči. Ale s PWA můžeme věci ukládat do mezipaměti pomocí samotného kódu na straně klienta, který není k dispozici ve webové aplikaci.
  • Publikování v obchodě (App/Play): PWA lze publikovat v Obchodě Google Play a IOS App Store.

Převedení vaší aplikace na PWA ji pouze učiní výkonnější.

Proč by podniky měly zvážit PWA

Zatímco většina našich klientů nás kontaktuje a žádá nejprve o vývoj řešení webové aplikace, a poté požádají o aplikace pro Android a iOS. Vše, co uděláme, je vytvořit stejnou funkcionalitu ve webové aplikaci pro Android/IOS aplikací samostatným týmem, což vyžaduje vyšší náklady na vývoj a více času na uvedení na trh.

Někteří klienti však mají omezený rozpočet nebo si někteří klienti mohou myslet, že čas uvedení na trh je pro jejich produkt důležitější.

Většinu požadavků klienta mohou uspokojit samotné funkce PWA. Pro ně doporučujeme pouze PWA a dáme jim nápad převést jejich PWA jako aplikaci pro Android pomocí TWA, pokud chtějí nasadit v Obchodě Play.

Pokud váš požadavek skutečně potřebuje funkce nativní aplikace, které PWA nemůže uspokojit. Klienti mohou jít a vyvíjet obě aplikace, jak chtějí. Ale i v takovém scénáři. Mohou nasadit PWA v obchodě Play, dokud nebude dokončen vývoj Androidu.

Příklad: Titan Eyeplus

Zpočátku vyvinuli aplikaci PWA a nasadili ji v obchodě Play pomocí TWA (Trusted Web Activity). Jakmile dokončili vývoj aplikací pro Android. Nasadili svou skutečnou aplikaci pro Android v obchodě Play. Dosáhli jak doby uvedení na trh pomocí PWA, tak nákladů na vývoj.

Vlastnosti PWA

PWA poskytuje našim webovým aplikacím nativní funkce podobné aplikacím.

Hlavní rysy jsou:

  • Instalovatelné: Webová aplikace nainstalovaná jako nativní aplikace.
  • Ukládání do mezipaměti: Ukládání aplikací do mezipaměti je možné, což poskytuje naší aplikaci offline podporu.
  • Push Notification: Push Notification může být zasláno z našeho serveru, aby přilákalo naše uživatele na naše webové stránky.
  • Geofencing: Aplikace může být upozorněna událostí při každé změně polohy zařízení.
  • Žádost o platbu: Povolte platbu ve své aplikaci se skvělým uživatelským zážitkem, jako je nativní aplikace.

A mnoho dalších funkcí, které přijdou v budoucnu.

  Jak sdílet hesla Wi-Fi z Androidu na jakýkoli smartphone

Další funkce jsou:

  • Zkratky: Rychle dostupné adresy URL přidané do souboru manifestu.
  • Web Share API: Umožněte vaší aplikaci přijímat sdílená data z jiných aplikací.
  • Badge API: Zobrazení počtu oznámení ve vašem nainstalovaném PWA.
  • Periodická synchronizace na pozadí API: ukládá data vašeho uživatele, dokud se nepřipojí k síti.
  • Výběr kontaktů: Používá se k výběru kontaktů z mobilu uživatele.
  • File Picker: Používá se pro přístup k souboru v místním systému/mobilu

Výhoda PWA oproti nativní aplikaci

Nativní aplikace funguje lépe než PWA a má více funkcí než PWA. Přesto má oproti nativní aplikaci určité výhody.

  • PWA běží na různých platformách, jako je Android, IOS, Desktop.
  • Snižuje vaše náklady na vývoj.
  • Snadné nasazení funkcí ve srovnání s nativní aplikací.
  • Snadno zjistitelné, protože PWA (web) je šetrný k SEO
  • Zabezpečené, protože funguje pouze na HTTPS

Nevýhody PWA oproti nativní aplikaci

  • Ve srovnání s nativní aplikací jsou k dispozici omezené funkce.
  • Funkce PWA nezaručují podporu všech zařízení.
  • Značka PWA je nízká, protože není k dispozici v obchodě s aplikacemi ani v obchodě Play.

Své PWA můžete nasadit jako aplikaci pro Android v obchodě Play pomocí Androidu Důvěryhodná webová aktivita (TWA). Pomůže to vaší značce.

Věci potřebné k převodu webové aplikace na PWA

Pro převod jakékoli webové aplikace nebo webu na PWA.

  • Service-Worker: jádro jakékoli aplikace PWA pro ukládání do mezipaměti, push Notification, proxy pro naše požadavky.
  • Soubor manifestu: Obsahuje podrobnosti o vaší webové aplikaci. Kdysi stahoval naši aplikaci jako nativní aplikaci na domovskou obrazovku.
  • Logo aplikace: Vysoce kvalitní obrázek 512 x 512 pixelů pro ikonu vaší aplikace. Logo aplikace potřebné pro PWA na domovské obrazovce, úvodní obrazovce atd. Musíme tedy pomocí jakýchkoli nástrojů vytvořit sadu obrázků s poměrem stran 1:1 pro naši aplikaci.
  • Responzivní design: Webová aplikace by měla reagovat na práci na různých velikostech obrazovky.

Co je servisní pracovník:

Servisní pracovník (skript na straně klienta) je proxy mezi vaší webovou aplikací a vnější stranou, doručuje push notifikace pro naši webovou aplikaci a podporuje ukládání do mezipaměti.

Service Worker běží nezávisle na hlavním javascriptu. Nemá tedy přístup k DOM API. Může pouze přistupovat IndexedDB API, Načíst API, Rozhraní API úložiště mezipaměti. Ale může komunikovat s hlavním vláknem pomocí zprávy.

Servis zajišťuje servisní pracovník:

  • Zachycování požadavků HTTP z vaší původní domény.
  • Přijímat oznámení Push ze serveru.
  • Offline dostupnost naší aplikace

Servisní pracovník řídí vaši aplikaci a může manipulovat s vašimi požadavky, ale běží nezávisle. Z tohoto důvodu musí být původní doména povolena pomocí HTTPS, aby se zabránilo útoku typu man-in-the-middle.

Co je soubor Manifest

Soubor manifestu (manifest.json) obsahuje podrobnosti o naší aplikaci PWA, které sdělí prohlížeči.

  • name: Název aplikace
  • short_name: Krátký název pro naši aplikaci. Pokud je poskytnuta
  • s názvem vlastnosti i short_name bude prohlížeč používat short_name.
  • popis: Popis k popisu naší aplikace.
  • start_url: Chcete-li určit domovskou stránku aplikace při spuštění našeho PWA.
  • ikony: Sada obrázků pro PWA pro domovskou obrazovku atd.
  • background_color: Chcete-li nastavit barvu pozadí úvodní obrazovky v naší aplikaci PWA.
  • displej: Chcete-li přizpůsobit uživatelské rozhraní prohlížeče tak, aby se zobrazovalo v naší aplikaci PWA.
  • theme_color: Barva motivu aplikace PWA.
  • rozsah: Rozsah adres URL naší aplikace, který je třeba zvážit pro PWA. Výchozí je umístění umístěného souboru manifestu.
  • zkratky: Rychlé odkazy pro naši aplikaci PWA.

Převést webovou aplikaci na PWA

Pro účely ukázky jsem vytvořil strukturu složek webu etechblog.cz se statickými soubory.

  • 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

Pokud již máte nějaké webové stránky nebo webovou aplikaci, zkuste je převést na PWA podle níže uvedených kroků.

Vytvořte požadované obrázky pro PWA

Nejprve vezměte logo své aplikace a ořízněte ho v poměru 1:1 na 5 různých velikostí. použil jsem https://tools.crawlink.com/tools/pwa-icon-generator/ pro rychlé získání různých velikostí obrázků. Můžete ho tedy použít i vy.

Vytvořte soubor manifestu

Zadruhé vytvořte soubor manifest.json pro webovou aplikaci s podrobnostmi o aplikaci. Pro ukázku jsem vytvořil soubor 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"
			}]
		}
	]
}

Registrovat servisního pracovníka

vytvořte soubor skriptu register-service-worker.js a service-worker.js v kořenové složce.

  Jak odinstalovat BetterDiscord na PC

První z nich, register-service-worker.js, je javascriptový soubor, který poběží v hlavním vláknu, které má přístup k DOM API. Ale service-worker.js je skript service worker, který běží nezávisle na hlavním vlákně a jeho životnost je také krátká. Spouští se vždy, když události volají servisní pracovníky, a běží, dokud nedokončí proces.

Kontrolou javascriptového souboru hlavního vlákna můžete zkontrolovat, zda je v něm servisní pracovník registrován. pokud ne, můžete zaregistrovat skript service worker (service-worker.js).

vložte níže uvedený úryvek do souboru register-service-worker.js:

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

Vložte níže uvedený fragment do 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.
});

Nesoustředili jsme se na to, jak povolit mezipaměť pro podporu offline. Mluvíme pouze o tom, jak převést webové aplikace na PWA.

Přidejte soubor manifestu a skript do značky all head na stránce HTML.

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

Po přidání stránku obnovte. Nyní si můžete nainstalovat aplikaci, jak je uvedeno níže, do mobilního Chrome.

Na domovské obrazovce se aplikace přidá.

Pokud používáte WordPress. Zkuste použít stávající plugin pro převodník PWA. Pro vueJS nebo reagJS můžete postupovat podle výše uvedené metody nebo použít stávající moduly PWA npm k urychlení vašeho vývoje. Protože moduly PWA npm jsou již povoleny s offline podporou ukládání do mezipaměti atd.

Povolit Push Notification

Webová oznámení push se odesílají do prohlížeče, aby naši uživatelé častěji zapojovali/interagovali s naší aplikací. Můžeme to povolit pomocí

  • Notifikační API: Používá se ke konfiguraci toho, jak se má uživateli zobrazovat naše oznámení push.
  • Push API: Používá se k přijímání upozornění odeslaných z našeho serveru do prohlížeče.

Prvním krokem k aktivaci push notifikace v naší aplikaci je zaškrtnutí Notification API a získání povolení od uživatele zobrazovat upozornění. Za tímto účelem zkopírujte a vložte níže uvedený úryvek 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ě. Obdržíte upozornění z aplikace.

„Oznámení“ v okně nám řekne, že tento prohlížeč podporuje rozhraní API pro oznámení. Notification.permission sdělí, že uživateli bylo povoleno zobrazit oznámení. Pokud uživatel povolil naší aplikaci, hodnota bude „udělena“. pokud uživatel odmítl, hodnota bude ‚blokována‘.

Povolit Firebase Cloud Messaging a vytvořit předplatné

Nyní začíná ta pravá část. Pro odesílání oznámení z vašeho serveru uživateli potřebujeme jedinečný koncový bod/předplatné pro každého uživatele. K tomu použijeme cloudové zprávy firebase.

Jako první krok si vytvořte účet Firebase kliknutím na tento odkaz https://firebase.google.com/ a stiskněte tlačítko Start.

  • Vytvořte nový projekt s názvem a stiskněte pokračovat. Vytvořím to s názvem etechblog.cz.
  • V dalším kroku je služba Google Analytics ve výchozím nastavení povolena. Můžete přepnout, že to teď nepotřebujeme, a stisknout pokračovat. V případě potřeby jej můžete povolit později v konzole Firebase.
  • Jakmile bude projekt vytvořen, bude vypadat jako níže.
  • Poté přejděte do nastavení projektu a klikněte na cloudové zprávy a vygenerujte klíče.

    Z výše uvedených kroků máte 3 klíče.

    • projektový serverový klíč
    • Webové push certifikáty soukromý klíč
    • Webové push certifikáty veřejný klíč

    Nyní vložte níže uvedený úryvek 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íže uvedený fragment do 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)
    });

    Nyní vše nastaveno ve front-endu. Pomocí předplatného můžete svému uživateli posílat oznámení push kdykoli chcete, dokud mu nebudou odepřeny služby push.

      Jak nastavit rutiny asistenta v Hodinách Google na Androidu

    Push z backendu node.js

    Můžete použít web-push modul npm, aby to bylo jednodušší.

    Příklad úryvku pro odeslání oznámení push ze serveru nodeJS.

    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 });
        });

    Výše uvedený kód odešle předplatnému oznámení push. Spustí se událost push v service-workeru.

    Push z PHP Backendu

    Pro PHP backend můžete použít web-push-php skladatelský balíček. Podívejte se na ukázkový kód pro zasílání oznámení push níže.

    <?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

    Doufám, že vám to poskytne představu o převodu webových aplikací na PWA. Můžete zkontrolovat zdrojový kód tohoto článku tady a demo to tady. Testoval jsem oznámení push odesláním z backendu také pomocí ukázkového kódu.

    x