Desde hace unos años se habla cada vez más de las Progressive Web Apps o PWAs como el futuro de las aplicaciones móviles y, lo cierto, es que el desarrollo de una PWA en lugar de una aplicación nativa cada vez está más justificado.
Las ventajas que presenta el desarrollo de una PWA son muchas pero sobretodo destacan:
- Implementación sencilla sobre un proyecto web. Esto, evidentemente, también implica unos menores costes de desarrollo.
- Funcionan prácticamente en todos los dispositivos (tanto móviles como de escritorio) y en prácticamente cualquier sistema operativo.
- Mantenimiento más sencillo al no tener que mantener distintas versiones para distintos dispositivos y sistemas operativos.
- Se instalan directamente desde el navegador sin depender de ningún mercado de aplicaciones.
Desarrollo de una PWA
Una de las grandes ventajas que tienen las PWAs es que puedes implementarlas sobre un proyecto ya en producción ya que tan solo, en su versión más sencilla, hay que implementar tres componentes: manifest.json, service-worker.js y offline.html.
Manifest.json
Ese archivo JSON establece las siguientes variables:
- name: nombre de la aplicación
- short_name: nombre corto de la aplicación
- icons: declaración de los iconos de la aplicación
- start_url: página de inicio de la aplicación
- display: standalone (aplicación independiente), browser (como una página web), fullscreen (pantalla completa)
- background_color: color de fondo al iniciar la aplicación
- theme_color: el color del tema usado en la aplicación
Un ejemplo sería:
{
"name": "Mi PWA",
"short_name": "Mi PWA",
"icons": [{
"src": "/images/icons/icon-128x128.png",
"sizes": "128x128",
"type": "image/png"
}, {
"src": "/images/icons/icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
}, {
"src": "/images/icons/icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
}, {
"src": "/images/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
}, {
"src": "/images/icons/icon-256x256.png",
"sizes": "256x256",
"type": "image/png"
}, {
"src": "/images/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png"
}],
"start_url": "/index.html",
"display": "standalone",
"background_color": "#FFFFFF",
"theme_color": "#FFFFFF"
}
Una vez implementado tendremos que enlazarlo en la(s) página(s) desde donde queramos que se pueda instalar junto con alguna que otra meta etiqueta adicional en el <head>:
<head>
[...]
<!-- Enlace al manifest.json -->
<link rel="manifest" href="/manifest.json">
<!-- Apple touch icon -->
<link rel="apple-touch-icon" href="/images/icons/icon-152x152.png">
<!-- Declaración de descripción y color del tema -->
<meta name="description" content="Descripción de la PWS">
<meta name="apple-mobile-web-app-title" content="Descripción de la PWS">
<meta name="theme-color" content="#FFFFFF" />
<!-- Otras meta etiquetas para iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
</head>
Service-worker.js
Se trata de un archivo escrito en JavaScript que el navegador ejecuta en segundo plano permitiendo realizar funciones que no necesitan ni a la página web ni la interacción de usuario (como puede ser una notificación push).
En el ejemplo que vamos a ver a continuación, el service worker se encarga de la instalación, chacheado y de qué hacer cuando no hay conexión a internet:
'use strict';
const CACHE_NAME = 'static-cache-v1';
const FILES_TO_CACHE = [
'/offline.html',
];
self.addEventListener('install', (evt) => {
console.log('[ServiceWorker] Install');
evt.waitUntil(
caches.open(CACHE_NAME).then((cache) => {
console.log('[ServiceWorker] Pre-caching offline page');
return cache.addAll(FILES_TO_CACHE);
})
);
self.skipWaiting();
});
self.addEventListener('activate', (evt) => {
console.log('[ServiceWorker] Activate');
evt.waitUntil(
caches.keys().then((keyList) => {
return Promise.all(keyList.map((key) => {
if (key !== CACHE_NAME) {
console.log('[ServiceWorker] Removing old cache', key);
return caches.delete(key);
}
}));
})
);
self.clients.claim();
});
self.addEventListener('fetch', (evt) => {
console.log('[ServiceWorker] Fetch', evt.request.url);
if (evt.request.mode !== 'navigate') {
return;
}
evt.respondWith(
fetch(evt.request)
.catch(() => {
return caches.open(CACHE_NAME)
.then((cache) => {
return cache.match('offline.html');
});
})
);
});
Como sucedía en el manifest.json, una vez implementado el service worker tendremos que llamarlo en la(s) página(s) desde donde queramos que se pueda instalar la PWA:
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js')
.then((reg) => {
console.log('Service worker registered.', reg);
});
});
}
</script>
Además, como ya se puede ver hacemos alusión al tercer y último elemento: la página sin conexión offline.html
Offline.html
Ésta es la parte más fácil ya que el offline.html tan solo es una página que se muestra cuando no hay conexión. Si eres buena con JavaScript puedes llegar a hacer virguerías para tener a tus usuarias entretenidas cuando no haya conexión 🙂
Si todo ha ido bien, cuando visites tu PWA, te saldrá un banner para añadir a la pantalla de inicio como el siguiente en el pie:
Por último, comentar que en la consola de desarrollo de Chrome encontramos dos herramientas muy potentes para el desarrollo de una PWA:
- Audits: nos permite auditar una Progressive Web App y comprobar que todo es correcto.
- Application: nos permite revisar si todos los componentes de nuestra aplicación están funcionando correctamente.
Resumiendo, con tan solo tres elementos puedes hacer que las personas que visiten tu proyecto lo instalen en sus dispositivos con los beneficios que ello conlleva: incremento de interacción, comunicación directa con tus usuarias (notificaciones push), etc.
Si quieres ampliar información sobre el desarrollo de una PWA puedes visitar el curso oficial de Google developers.
Como siempre, si tienes alguna duda o aportación, no dudes en dejar un comentario.