Fino a qualche anno fa, utilizzando un device mobile, l’utente poteva scegliere solo tra due classi di applicazioni: le applicazioni mobile native (quindi scritte in codice nativo per Android o Iphone e scaricate dall’App Store) oppure le Web App, ossia pagine web che richiedevano un browser per funzionare, ma che, grazie a uno stile di programmazione evoluto, offrivano features responsive e un’interfaccia utente con cui cercavano di avvicinarsi molto all’esperienza offerta da una app nativa.
Cos’è una Progressive Web App
Grazie ai continui miglioramenti introdotti in HTML5, CSS e Javascript, in questi ultimi tempi si è sempre più diffusa una terza alternativa che viene offerta all’utente di device mobili, ossia quella delle Progressive App. Le Progressive App sono app che funzionano in un browser, ma che hanno due particolarità che le distinguono nettamente dalle Web App di precedente generazione:
- l’esperienza utente (UI/UX) è praticamente indistinguibile da quella di una app nativa;
- un insieme di funzionalità viene reso fruibile anche in assenza di connessione internet.
Caratteristiche di una app progressiva
Una app progressiva (PWA: Progressive Web App) è un termine coniato dagli sviluppatori Alex Russell e Frances Berriman, e rappresenta un set di best practice per rendere una pagina web il più simile possibile a una app nativa per device mobile, offrendo un’esperienza utente piacevole ed eliminando la necessità di dover passare da un processo di installazione. Inoltre, le PWA, pur essendo eseguite dentro a un browser, offrono la possibilità di creare un collegamento direttamente nella home dello smartphone, permettendo all’utente di richiamarle come delle vere e proprie app native. Questo risultato è ottenuto grazie all’impiego di diverse tecnologie di programmazione, le più importanti delle quali sono i Service Worker, il manifesto dell’app (Manifest) e l’impaginazione Responsive.
Che cos’è un service worker
La tecnologia che sta alla base di questo innovativo modo di creare pagine web è quella del service worker, un programma scritto in Javascript che viene eseguito parallelamente alla “solita” pagina web e che permette di arricchire la fruizione del documento web di funzionalità aggiuntive. Ma vediamo nel dettaglio di che cosa si tratta.
Il service worker è un worker Javascript, ossia un servizio che viene eseguito in un suo thread e che non comunica direttamente con la struttura del documento della pagina (il cosiddetto DOM), ma che può accedervi solo grazie alla classica interfaccia Javascript di PostMessage. In questo modo il service worker può effettuare delle elaborazioni in background senza interferire con l’esperienza utente della pagina web, esattamente come accade nelle app mobile, dove l’utente interagisce con la pagina mentre un servizio in background esegue le elaborazioni necessarie alle operazioni sui dati e alla gestione dell’app.
Il service worker sostituisce completamente quella che era la vecchia app cache. Il service worker deve essere installato e registrato, e ha bisogno di una connessione Https per funzionare correttamente. Una volta installato, il service worker può effettuare operazioni di connessione ai dati (“fetching”), che può immagazzinare e rendere disponibili anche per una interazione offline, permettendo all’utente di accedere in modo parziale a funzionalità dell’app anche se la connessione a internet è assente.
Grazie al Service Worker, la pagina web può delegare a questo servizio in background attività che, altrimenti risulterebbero difficili da integrare con una fluida risposta agli input dell’utente, come ad esempio la gestione delle notifiche push, la sincronizzazione dei dati, e la risposta a eventi generati da applicazioni di terze parti.
Il Manifest
Il Manifest è una sorta di dichiarazione di alcune delle proprietà principali che permettono all’app di interfacciarsi all’ambiente software destinato ad ospitarla, ed è una feature che troviamo già presente nelle app native per device mobile.
Nel caso dell’app progressiva, il Manifest contiene alcuni dei metadati chiave per l’esecuzione dell’app, che permettono al sistema operativo dello smartphone di interagire con la pagina web come se si trattasse di una app installata nativamente. Alcune delle proprietà gestite tramite il Manifest sono, ad esempio, l’orientamento iniziale dell’app e l’informazione se l’app debba essere eseguita o meno a dimensioni full screen, oltre alle informazioni necessarie allo user agent per l’installazione della web app e il suo nome. Il Manifest contiene inoltre informazioni sulle autorizzazioni che l’utente deve concedere affinché l’app possa eseguire correttamente quelle funzionalità che hanno bisogno di accedere a funzioni del sistema operativo con impatto sulla privacy (ad esempio, la geolocalizzazione del dispositivo) o a documenti salvati sullo storage dello smartphone.
Responsive App Shell
L’ultima caratteristica delle app progressive è l’implementazione di una interfaccia Responsive. Il design Responsive non è una novità propria delle PWA: è una tecnica di realizzazione dell’interfaccia utente che risale al periodo dell’apparizione sul mercato dei primi smartphone. Consiste nel creare pagine e controlli che si ridimensionano automaticamente a seconda della grandezza dello schermo su cui vengono eseguite, in modo che l’esperienza utente risulti piacevole su qualsiasi dispositivo la pagina venga visualizzata. Il design responsive è stato inizialmente implementato nei siti web con una combinazione di tecniche CSS, Javascript e HTML per poi evolversi in veri e propri framework come Bootstrap o React.
Nel contesto della Web App Progressive, però, sebbene il Responsive Design non sia di per sé una novità tecnologica, assume invece nuove connotazioni per sfruttare le potenzialità offerte dalla WPA. Nel contesto WPA, infatti, non si parla soltanto di Responsive web design, ma di una vera e propria Responsive Shell, o App Shell.
L’App Shell è lo scheletro minimale dell’app che stiamo andando a confezionare, e permette il caricamento di tutte quelle che saranno le funzionalità base dell’app, a cui poi potranno essere caricate, progressivamente, tutte le altre risorse necessarie alle operazioni che l’utente deciderà di effettuare, tramite un efficiente meccanismo di lazy loading. Stiamo quindi parlando di un innovativo pattern nella costruzione dell’architettura di una pagina web, che permette di effettuare un download iniziale solo delle risorse strettamente necessarie al funzionamento dell’app, evitando così noiose operazioni di installazione dall’App Store.
Una App Shell si compone di tre sezioni fondamentali:
- la Critical Inline Style: semplificando, l’equivalente di quella che in una pagina web è la sezione head, contenente le specifiche CSS dell’app;
- la sezione HTML, che definisce il vero e proprio corpo (Document Object Model) dell’app;
- la sezione dei Critical Script, che si occupa di richiamare gli script Javascript necessari al funzionamento dell’app.
L’esecuzione degli script viene gestita attraverso il duplice meccanismo dell’esecuzione asincrona e differita: l’attivazione asincrona (async) permette di eseguire lo script in maniera trasparente per l’utente, mentre la specifica defer permette di gestire eventuali problemi di ordine di download degli script, evitando conflitti di priorità nell’esecuzione degli script.
La caratteristica principale della App Shell è di permettere all’app di godere di un subset di funzionalità eseguibili anche mentre l’app è offline, o sotto una copertura internet di bassa qualità. Questo risultato è ottenuto grazie al meccanismo della Network Strategy.
La Network Strategy
La Network Strategy (o Workbox Strategy) entra in gioco per permettere al Service Worker di effettuare decisioni riguardanti il caricamento dei dati. Per poter permettere all’app di funzionare anche offline, il Service Worker deve infatti definire delle priorità di caricamento dati che gli consentano di gestire in modo ottimale anche le funzioni dell’app che devono funzionare in assenza di collegamento internet.
La Network Strategy permette infatti al Service Worker di decidere in autonomia se caricare le risorse che servono a svolgere un determinato processo da una cache offline oppure se andarle a reperire da un endpoint online, che richiede quindi una connessione internet attiva. Nel caso che le risorse vengano reperite dalla cache, un sistema di aggiornamenti periodici a connessione disponibile garantisce che i dati presenti in cache siano coerenti con l’interfaccia della funzionalità offline.