Acest articol explorează modalitatea de a transforma o aplicație web sau un site web într-o PWA (Progressive Web App), beneficiind de notificări push prin Firebase Cloud Messaging.
În prezent, tendința este de a converti majoritatea aplicațiilor web în PWA, datorită avantajelor precum suportul offline, notificările push și sincronizarea în fundal. Aceste caracteristici PWA îmbunătățesc experiența utilizatorului, apropiind aplicația web de funcționalitățile unei aplicații native.
Companii de renume, precum Twitter și Amazon, au adoptat această transformare, convertindu-și aplicațiile web în PWA pentru a crește interacțiunea utilizatorilor.
Ce reprezintă o PWA?
PWA = Aplicație web + funcții specifice aplicațiilor native.
O PWA este, în esență, o aplicație web (HTML, CSS, JS) care funcționează similar pe toate browserele. Totuși, atunci când este accesată printr-un browser modern, poate oferi funcții native. Acest lucru o face mai eficientă și scalabilă, permițând stocarea în cache a elementelor de frontend și reducând solicitările către serverul backend.
Cum se diferențiază o PWA de o aplicație web?
- Instalabilă: Poate fi instalată ca o aplicație nativă pe dispozitiv.
- Progresivă: Funcționează ca o aplicație web standard, dar cu caracteristici native.
- Experiență similară aplicației native: Odată instalată, oferă utilizatorului o experiență de navigare similară cu o aplicație nativă.
- Acces facil: Nu mai este necesară introducerea adresei web la fiecare vizită, fiind accesibilă direct printr-o singură atingere.
- Memorare în cache îmbunătățită: Spre deosebire de mecanismul de cache HTTP tradițional al aplicațiilor web, PWA permite stocarea în cache direct din codul clientului, oferind mai mult control.
- Publicare în magazinele de aplicații: O PWA poate fi listată în magazinele Google Play Store și Apple App Store.
Convertirea aplicației tale în PWA nu face decât să o îmbunătățească.
De ce ar trebui companiile să ia în considerare PWA?
Adesea, clienții solicită inițial dezvoltarea unei aplicații web, urmată de aplicații separate pentru Android și iOS. Această abordare implică echipe distincte, ceea ce duce la costuri de dezvoltare mai mari și un timp de lansare pe piață prelungit.
Pentru clienții cu un buget limitat sau care consideră timpul de lansare pe piață un factor crucial, PWA reprezintă o soluție excelentă.
Multe cerințe ale clienților pot fi îndeplinite prin funcțiile PWA. Pentru aceștia, sugerăm PWA și oferim posibilitatea de a le transforma în aplicații Android prin TWA (Trusted Web Activity), dacă doresc publicarea în Play Store.
În situațiile în care sunt necesare funcții native specifice, neimplementabile în PWA, clienții pot opta pentru dezvoltarea ambelor tipuri de aplicații. Chiar și în acest caz, PWA poate fi lansată în magazinele de aplicații ca soluție intermediară până la finalizarea aplicației native.
Exemplu: Titan Eyeplus a lansat inițial o PWA în magazinul de aplicații prin TWA, lansând ulterior aplicația nativă Android după finalizarea dezvoltării. Această strategie a permis respectarea termenului de lansare pe piață și gestionarea eficientă a costurilor.
Funcționalități PWA
PWA aduce funcții native tipice aplicațiilor mobile în mediul web.
Principalele funcționalități sunt:
- Instalabilă: Aplicația web poate fi instalată ca o aplicație nativă pe dispozitivul utilizatorului.
- Memorarea în cache: Permite stocarea în cache, oferind suport offline aplicației.
- Notificări push: Notificările push pot fi trimise de pe server pentru a menține utilizatorii implicați.
- Geofencing: Aplicația poate trimite notificări în funcție de schimbările de locație ale dispozitivului.
- Soluții de plată: Facilitează integrarea plăților în aplicație, oferind o experiență similară aplicațiilor native.
Și multe alte funcționalități sunt în curs de dezvoltare.
Alte funcții includ:
- Comenzi rapide: Permite acces rapid la URL-uri, definite în fișierul manifest.
- Web Share API: Permite aplicației să primească date de la alte aplicații.
- API Badge: Afișează un număr de notificări pe pictograma PWA instalată.
- API Periodic Background Sync: Salvează datele utilizatorului în fundal până la reconectarea la rețea.
- Selector de contacte: Oferă acces la lista de contacte a utilizatorului.
- Selector de fișiere: Permite accesul la fișierele de pe sistemul local.
Avantajele PWA față de aplicațiile native
Deși aplicațiile native sunt, în general, superioare ca performanță și funcționalitate, PWA prezintă anumite avantaje:
- Compatibilitate multiplatformă: PWA rulează pe diverse sisteme, inclusiv Android, iOS și desktop.
- Costuri reduse de dezvoltare: Dezvoltarea este mai economică în comparație cu aplicațiile native.
- Implementare simplă: Implementarea funcțiilor este mai simplă decât în cazul aplicațiilor native.
- Vizibilitate: PWA sunt mai ușor de descoperit, fiind compatibile cu SEO.
- Securitate: Funcționează exclusiv pe protocolul HTTPS.
Dezavantajele PWA față de aplicațiile native
- Funcționalitate limitată: Oferă mai puține funcții în comparație cu aplicațiile native.
- Compatibilitate limitată: Nu toate dispozitivele suportă integral funcțiile PWA.
- Branding redus: Fiindcă nu se află direct în magazinele de aplicații, brandingul este mai slab.
Totuși, o PWA poate fi publicată ca aplicație Android în Play Store folosind Trusted Web Activity (TWA), ceea ce ajută la consolidarea brandingului.
Ce este necesar pentru a transforma o aplicație web în PWA?
Pentru a transforma o aplicație web sau un site web în PWA, sunt necesare următoarele:
- Service Worker: Componenta principală a oricărei PWA, responsabilă de caching, notificări push și gestionarea cererilor.
- Fișier manifest: Conține informații despre aplicația web, necesare pentru instalarea ca aplicație nativă pe ecranul de start.
- Logo-ul aplicației: O imagine de înaltă calitate (512×512 px) pentru pictograma aplicației, utilizată pe ecranul de pornire și în diverse locuri ale interfeței. Este necesară o serie de imagini cu raport 1:1 create cu ajutorul unor instrumente dedicate.
- Design responsive: Aplicația web trebuie să fie responsivă și să funcționeze corect pe diverse dimensiuni de ecran.
Ce este un Service Worker?
Un Service Worker este un script care acționează ca un proxy între aplicația web și exterior, furnizând notificări push și gestionând caching-ul.
Service Worker rulează independent de firul principal JavaScript, neavând acces la DOM API. Poate accesa doar IndexedDB API, Fetch API și Cache Storage API. Poate comunica cu firul principal prin intermediul mesajelor.
Serviciile oferite de un Service Worker:
- Interceptarea cererilor HTTP din domeniul sursă.
- Recepționarea notificărilor push de pe server.
- Asigurarea funcționalității offline a aplicației.
Deoarece Service Worker controlează aplicația și manipulează cererile independent, domeniul sursă trebuie să utilizeze HTTPS pentru a preveni atacurile de tip „man-in-the-middle”.
Ce este fișierul Manifest?
Fișierul manifest (manifest.json) conține detalii despre PWA, pe care browserul le utilizează.
- name: Denumirea aplicației.
- short_name: O variantă scurtă a numelui aplicației, folosită atunci când spațiul este limitat. Dacă sunt specificate ambele,
short_name
are prioritate. - description: Descrierea aplicației.
- start_url: URL-ul paginii de start a aplicației, care este deschisă la lansarea PWA.
- icons: Un set de imagini pentru PWA, folosite pe ecranul de start și în alte locuri ale interfeței.
- background_color: Culoarea de fundal a ecranului de splash.
- display: Personalizează interfața browserului pentru a afișa aplicația PWA.
- theme_color: Culoarea temei PWA.
- scope: Domeniul URL luat în considerare de PWA, implicit locația fișierului manifest.
- shortcuts: Link-uri rapide către secțiuni specifice ale aplicației PWA.
Transformarea unei aplicații web în PWA
Pentru a demonstra, a fost creată o structură de foldere a site-ului tipstrick.ro cu fișiere statice:
- index.html – pagina de start
- articole/
- index.html – pagina de articole
- autori/
- index.html – pagina autorilor
- instrumente/
- index.html – pagina de instrumente
- oferte/
- index.html – pagina de oferte
Dacă aveți un site sau o aplicație web existentă, puteți încerca să o transformați într-o PWA urmând pașii de mai jos.
Crearea imaginilor necesare pentru PWA
Începeți prin a decupa sigla aplicației într-un raport de 1:1, creând 5 dimensiuni diferite. Se poate utiliza https://tools.crawlink.com/tools/pwa-icon-generator/ pentru a obține rapid aceste dimensiuni.
Crearea unui fișier manifest
Apoi, creați un fișier manifest.json cu detaliile aplicației web. Pentru demonstrație, a fost creat un fișier manifest pentru site-ul tipstrick.ro:
{ "name": "tipstrick.ro", "short_name": "tipstrick.ro", "description": "tipstrick.ro 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": "tipstrick.ro - Authors", "url": "/authors", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] }, { "name": "Tools", "short_name": "Tools", "description": "tipstrick.ro - Tools", "url": "https://tipstrick.ro.com/tools", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] }, { "name": "Deals", "short_name": "Deals", "description": "tipstrick.ro - Deals", "url": "/deals", "icons": [{ "src": "/assets/icon/icon-152x152.png", "sizes": "152x152" }] } ] }
Înregistrarea Service Worker-ului
Creați două fișiere: register-service-worker.js și service-worker.js în folderul rădăcină.
register-service-worker.js este un fișier JavaScript executat pe firul principal, care poate accesa DOM API, în timp ce service-worker.js este un script Service Worker care rulează independent și are un ciclu de viață mai scurt, activându-se la anumite evenimente și rulând până la finalizarea procesului.
În fișierul JavaScript al firului principal, verificați dacă Service Worker este înregistrat. Dacă nu, înregistrați scriptul Service Worker (service-worker.js).
Înserați următorul cod în register-service-worker.js:
if ('serviceWorker' in navigator) { window.addEventListener('load', function() { navigator.serviceWorker.register('/service-worker.js'); }); }
Lipiți următorul cod în service-worker.js:
self.addEventListener('install', (event) => { // eveniment la instalarea service worker-ului console.log( 'install', event); self.skipWaiting(); }); self.addEventListener('activate', (event) => { // eveniment la activarea service worker-ului console.log('activate', event); return self.clients.claim(); }); self.addEventListener('fetch', function(event) { // interceptor de cereri HTTP event.respondWith(fetch(event.request)); // trimite toate cererile http fără logica cache /*event.respondWith( caches.match(event.request).then(function(response) { return response || fetch(event. request); }) );*/ // memoreaza in cache cererile noi. Daca sunt deja in cache serveste din cache. });
În acest articol, accentul este pus pe conversia aplicațiilor web în PWA, nu pe activarea caching-ului pentru suport offline.
Adăugați fișierul manifest și scriptul în secțiunea <head> a paginii HTML:
<link rel="manifest" href="https://tipstrick.ro.com/manifest.json"> <script src="/register-service-worker.js"></script>
După actualizare, puteți instala aplicația ca mai jos pe Chrome mobil:
Aplicația este acum adăugată pe ecranul de start.
Dacă utilizați WordPress, utilizați un plugin de conversie PWA existent. Pentru VueJS sau ReactJS, puteți urma această metodă sau utiliza module PWA npm existente pentru a accelera dezvoltarea, acestea având deja activat suportul offline și caching.
Activarea notificărilor push
Notificările push web sunt transmise browserelor pentru a crește interacțiunea utilizatorilor. Pentru a le activa, se folosesc:
- Notification API: Utilizat pentru a configura modul de afișare a notificărilor push către utilizatori.
- Push API: Folosit pentru a primi mesajele de notificare trimise de server către browser.
Pentru a activa notificările push, verificați suportul pentru Notification API și solicitați permisiunea utilizatorului. Pentru aceasta, copiați și inserați următorul cod în 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); }); } };
Dacă totul merge bine, veți primi o notificare din aplicație.
„Notification” din fereastră indică faptul că Notification API este suportat de browser. Proprietatea „Notification.permission” arată dacă utilizatorul a permis afișarea notificărilor. Valoarea va fi „granted” dacă a permis, respectiv „blocked” dacă a refuzat.
Activarea Firebase Cloud Messaging și crearea abonamentului
Pentru a trimite notificări de la server către utilizatori, este necesar un punct final (abonament) unic pentru fiecare utilizator. Firebase Cloud Messaging este folosit în acest scop.
Pentru început, creați un cont Firebase de la link-ul https://firebase.google.com/.
- Creați un nou proiect cu un nume, de exemplu, tipstrick.ro.
- În pasul următor, Google Analytics este activat implicit. Puteți dezactiva această opțiune, dacă nu este necesară, și o puteți activa ulterior din consola Firebase.
- După crearea proiectului, veți vedea o imagine similară cu cea de mai jos:
Accesați setările proiectului și dați click pe opțiunea de Cloud Messaging și generați cheile.
După acești pași, veți avea acces la 3 chei:
- Cheia serverului proiectului.
- Certificatul push web cu cheie privată.
- Certificatul push web cu cheie publică.
Înserați următorul cod în register-service-worker.js:
const updateSubscriptionOnYourServer = subscription => { console.log('Scrieți codul ajax pentru salvarea abonamentului utilizatorului în BD', subscription); // scrieți propria metodă ajax folosind fetch, jquery, axios pentru a salva abonamentul în serverul dvs. pentru a putea fi utilizat ulterior. }; const subscribeUser = async () => { const swRegistration = await navigator.serviceWorker.getRegistration(); const applicationServerPublicKey = 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY'; // copiați cheia publică a certificatului webpush const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey); swRegistration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey }) .then((subscription) => { console.log('Utilizatorul s-a abonat nou:', subscription); updateSubscriptionOnServer(subscription); }) .catch((err) => { if (Notification.permission === 'denied') { console.warn('Permisiunea pentru notificări a fost refuzată') } else { console.error('Nu s-a reușit abonarea utilizatorului: ', 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('Utilizatorul este deja abonat.'); updateSubscriptionOnYourServer(subscription); } else { console.log('Utilizatorul NU este abonat. Abonați utilizatorul nou.'); subscribeUser(); } }); }; checkSubscription();
Lipiți următorul cod în 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) });
Acum totul este pregătit în frontend. Folosind abonamentul, puteți trimite notificări push utilizatorilor până la refuzul serviciilor push.
Push din backend-ul node.js
Puteți utiliza modulul npm web-push pentru o implementare mai simplă.
Următorul cod este un exemplu pentru a trimite notificări push de pe un server nodeJS.
const webPush = require('web-push'); // pushSubscription este abonamentul trimis din frontend pentru a fi salvat in BD const pushSubscription = {"endpoint":"https://updates.push.services.mozilla.com/wpush/v2/gAAAAABh2…E0mTFsHtUqaye8UCoLBq8sHCgo2IC7UaafhjGmVCG_SCdhZ9Z88uGj-uwMcg","keys":{"auth":"qX6AMD5JWbu41cFWE3Lk8w","p256dh":"BLxHw0IMtBMzOHnXgPxxMgSYXxwzJPxpgR8KmAbMMe1-eOudcIcUTVw0QvrC5gWOhZs-yzDa4yKooqSnM3rnx7Y"}}; //cheia publică a certificatului dvs. web const vapidPublicKey = 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE3IcC52hJDYsY'; //cheia privată a certificatului dvs. web const vapidPrivateKey = 'web-certificate private key'; var payload = JSON.stringify({ "options": { "body": "Testarea notificărilor PWA din backend", "badge": "/assets/icon/icon-152x152.png", "icon": "/assets/icon/icon-152x152.png", "vibrate": [100, 50, 100], "data": { "id": "458", }, "actions": [{ "action": "view", "title": "Vizualizare" }, { "action": "close", "title": "Închide" }] }, "header": "Notificare de la tipstrick.ro-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 : 'Notificare trimisă'}); }).catch(err => { return res.json({status : false, message : err }); });
Acest cod trimite o notificare push către abonament, declanșând evenimentul push din service worker.
Push din backend-ul PHP
Pentru backend-ul PHP, puteți utiliza pachetul composer web-push-php. Exemplul de cod de mai jos arată cum să trimiteți notificări push:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed'); require __DIR__.'/../vendor/autoload.php'; use MinishlinkWebPushWebPush; use MinishlinkWebPushSubscription; // abonament stocat in BD $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' => 'Testarea notificărilor PWA din 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' => 'Vizualizare', ), 1 => array ( 'action' => 'close', 'title' => 'Închide', ), ), ), 'header' => 'Notificare de la tipstrick.ro-PWA Demo', ); // autentificare $auth = [ 'GCM' => 'cheia privată a proiectului dvs.', // deprecated și opțional, doar pentru compatibilitate 'VAPID' => [ 'subject' => 'mailto:[email protected]', // poate fi mailto: sau adresa site-ului 'publicKey' => 'BOcTIipY07N4Y63Y-9r7NMoJHofmCzn3Pu9g-LMsgIMGH4HVr42_LW9ia0lMr68TsTLKS3UcdkE