Cómo convertir WebApp como PWA con notificación push

En este artículo, vemos cómo convertir una aplicación web o un sitio web en una PWA con una notificación automática utilizando Firebase Cloud Messaging.

En el mundo moderno, la mayoría de las aplicaciones web se están convirtiendo en una PWA (aplicación web progresiva) porque proporciona funciones como soporte sin conexión, notificación automática y sincronización en segundo plano. Las características de PWA hacen que nuestra aplicación web se parezca más a una aplicación nativa y brinda una experiencia de usuario rica.

Por ejemplo, grandes empresas como Twitter y Amazon han convertido su aplicación web a PWA para lograr una mayor participación de los usuarios.

¿Qué es una PWA?

PWA = (aplicación web) + (algunas características de la aplicación nativa)

PWA es tu misma aplicación web (HTML+CSS+JS). Funciona igual que su aplicación web en todos los navegadores como lo hacía anteriormente. Pero puede tener funciones nativas cuando su sitio web se carga en un navegador moderno. Hace que su aplicación web sea más poderosa que antes y también la hace más escalable porque podemos precargar y almacenar en caché los activos en el frontend, reduce las solicitudes a su servidor backend.

En qué se diferencia PWA de la aplicación web

  • Instalable: su aplicación web se puede instalar como una aplicación nativa
  • Progresivo: funciona igual que su aplicación web pero con algunas funciones nativas
  • Experiencia de aplicación nativa: el usuario puede usar y navegar la aplicación web como un nativo, una vez instalada.
  • Fácilmente accesible: a diferencia de nuestra aplicación web, no es necesario que nuestros usuarios escriban direcciones web cada vez que visitan. Una vez instalado, se puede abrir con un solo toque.
  • Almacenamiento en caché de aplicaciones: antes de PWA, el único mecanismo de almacenamiento en caché con el que se implementaba nuestra aplicación web era mediante el uso de caché HTTP, que solo está disponible para el navegador. Pero con PWA podemos almacenar cosas en caché utilizando el propio código del lado del cliente que no está disponible en una aplicación web.
  • Publicación en la tienda (App/Play): PWA se puede publicar en Google Play Store y IOS App Store.

Convertir su aplicación a PWA solo la hará más poderosa.

Por qué las empresas deberían considerar PWA

Si bien la mayoría de nuestros clientes se comunican con nosotros y nos piden desarrollar primero la solución de la aplicación web y luego solicitan las aplicaciones de Android e iOS. Todo lo que vamos a hacer es construir la misma funcionalidad en la aplicación web para la aplicación Android/IOS por un equipo separado, lo que implica más costos de desarrollo y más tiempo de comercialización.

Pero algún cliente tiene un presupuesto limitado o algún cliente puede pensar que el tiempo de comercialización es más importante para su producto.

La mayoría de los requisitos del cliente pueden satisfacerse con las funciones de PWA. Para ellos, sugerimos solo PWA y les damos una idea para convertir su PWA como una aplicación de Android usando TWA si quieren implementar en Playstore.

Si su requerimiento realmente necesita funciones de aplicaciones nativas que PWA no puede satisfacer. Los clientes pueden ir y desarrollar ambas Aplicaciones como deseen. Pero incluso en ese escenario. Pueden implementar el PWA en Play Store hasta que se complete el desarrollo de Android.

Ejemplo: Titan Eyeplus

Inicialmente, desarrollaron una aplicación PWA y la implementaron en Play Store usando TWA (actividad web confiable). Una vez que completaron el desarrollo de su aplicación Android. Implementaron su aplicación de Android real en Play Store. Consiguieron tanto el tiempo de comercialización con PWA como el coste del desarrollo.

Características de PWA

PWA brinda a nuestras aplicaciones web funciones nativas similares a las de una aplicación.

Las características principales son:

  • Instalable: una aplicación web instalada como una aplicación nativa.
  • Almacenamiento en caché: el almacenamiento en caché de la aplicación es posible, lo que brinda soporte fuera de línea a nuestra aplicación.
  • Notificación de inserción: la notificación de inserción se puede enviar desde nuestro servidor para atraer a nuestros usuarios a nuestro sitio web.
  • Geofencing: la aplicación puede ser notificada por un evento cada vez que cambia la ubicación del dispositivo.
  • Solicitud de pago: habilite el pago en su aplicación con una excelente experiencia de usuario como una aplicación nativa.

Y muchas más características por venir en el futuro.

Otras características son:

  • Accesos directos: URL de acceso rápido agregadas en el archivo de manifiesto.
  • Web Share API: permita que su aplicación reciba datos compartidos de otras aplicaciones.
  • Badge API: para mostrar el recuento de notificaciones en su PWA instalado.
  • API de sincronización periódica en segundo plano: guarda los datos de su usuario hasta que se conecta a la red.
  • Selector de contactos: Sirve para recoger contactos del móvil del usuario.
  • Selector de archivos: se utiliza para acceder al archivo en el sistema local/móvil

Ventaja de PWA sobre la aplicación nativa

La aplicación nativa funciona mejor que PWA y tiene más funciones que PWA. Pero aún así, tiene algunas ventajas sobre la aplicación nativa.

  • PWA se ejecuta en plataformas cruzadas como Android, IOS, Desktop.
  • Reduce su costo de desarrollo.
  • Fácil implementación de funciones en comparación con una aplicación nativa.
  • Fácilmente reconocible porque PWA (sitio web) es compatible con SEO
  • Seguro porque funciona solo en HTTPS

Desventajas de PWA sobre la aplicación nativa

  • Las funcionalidades limitadas están disponibles en comparación con una aplicación nativa.
  • No se garantiza que las características de PWA sean compatibles con todos los dispositivos.
  • La marca de PWA es baja porque no está disponible en la tienda de aplicaciones o en la tienda de juegos.

Puede implementar su PWA como una aplicación de Android en Play Store usando Android Actividad web de confianza (TWA). Ayudará a su marca.

Cosas necesarias para convertir la aplicación web a PWA

Para convertir cualquier aplicación web o sitio web a PWA.

  • Service-Worker: el núcleo de cualquier aplicación PWA para almacenamiento en caché, notificaciones push, un proxy para nuestras solicitudes.
  • Archivo de manifiesto: tiene detalles sobre su aplicación web. Solía ​​descargar nuestra aplicación como una aplicación nativa en la pantalla de inicio.
  • Logotipo de la aplicación: imagen de alta calidad de 512 x 512 px para el ícono de su aplicación. Se necesita el logotipo de la aplicación para PWA en la pantalla de inicio, la pantalla de inicio, etc. Por lo tanto, tenemos que crear un conjunto de imágenes de proporción 1: 1 para nuestra aplicación utilizando cualquier herramienta.
  • Diseño receptivo: la aplicación web debe ser receptiva para funcionar en diferentes tamaños de pantalla.

¿Qué es el trabajador de servicio?

Un trabajador de servicio (secuencia de comandos del lado del cliente) es un proxy entre su aplicación web y el lado externo, que entrega notificaciones automáticas para nuestra aplicación web y admite el almacenamiento en caché.

Service Worker se ejecuta independientemente del javascript principal. Entonces no tiene acceso a la API DOM. Solo puede acceder API de base de datos indexada, Obtener API, API de almacenamiento en caché. Pero puede comunicarse con el hilo principal con un mensaje.

Servicio proporcionado por el trabajador del servicio:

  • Interceptar solicitudes HTTP de su dominio de origen.
  • Reciba notificaciones automáticas de su servidor.
  • Disponibilidad sin conexión de nuestra aplicación

El trabajador del servicio controla su aplicación y puede manipular sus solicitudes, pero se ejecuta de forma independiente. Entonces, por esa razón, el dominio de origen debe estar habilitado con HTTPS para evitar un ataque de intermediario.

¿Qué es el archivo de manifiesto?

Un archivo de manifiesto (manifest.json) tiene detalles sobre nuestra aplicación PWA para informarle al navegador.

  • nombre: Nombre de la aplicación
  • short_name: Nombre corto para nuestra aplicación. Si se proporciona
  • con nombre de propiedad y nombre_corto, el navegador tomará nombre_corto.
  • description: Descripción para describir nuestra aplicación.
  • start_url: para especificar la página de inicio de la aplicación cuando se lanzó nuestra PWA.
  • iconos: conjunto de imágenes para PWA para la pantalla de inicio, etc.
  • background_color: para establecer el color de fondo de la pantalla de bienvenida en nuestra aplicación PWA.
  • pantalla: para personalizar la interfaz de usuario de nuestro navegador para que se muestre en nuestra aplicación PWA.
  • theme_color: color del tema de la aplicación PWA.
  • scope: ámbito URL de nuestra aplicación a considerar para PWA. El valor predeterminado es la ubicación del archivo de manifiesto que se encuentra.
  • accesos directos: enlaces rápidos para nuestra aplicación PWA.

Convertir aplicación web a PWA

Para fines de demostración, he creado una estructura de carpetas del sitio web kirukiru.es con archivos estáticos.

  • index.html – página de inicio
  • artículos/
    • index.html – página de artículos
  • autores/
    • index.html – página de autores
  • instrumentos/
    • index.html – página de herramientas
  • ofertas/
    • index.html – página de ofertas

Si ya tiene algún sitio web o aplicación web, intente convertirlo a PWA siguiendo los pasos a continuación.

Crear imágenes requeridas para PWA

En primer lugar, tome el logotipo de su aplicación y recórtelo en una proporción de 1:1 en 5 tamaños diferentes. he utilizado https://tools.crawlink.com/tools/pwa-icon-generator/ para obtener diferentes tamaños de imagen rápidamente. Así que tú también puedes usarlo.

Crear un archivo de manifiesto

En segundo lugar, cree un archivo manifest.json para su aplicación web con los detalles de su aplicación. Para la demostración, he creado un archivo de manifiesto para el sitio web kirukiru.es.

{
	"name": "kirukiru.es",
	"short_name": "kirukiru.es",
	"description": "kirukiru.es 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": "kirukiru.es - Authors",
			"url": "/authors",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		},
		{
			"name": "Tools",
			"short_name": "Tools",
			"description": "kirukiru.es - Tools",
			"url": "https://kirukiru.es.com/tools",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		},
		{
			"name": "Deals",
			"short_name": "Deals",
			"description": "kirukiru.es - Deals",
			"url": "/deals",
			"icons": [{
				"src": "/assets/icon/icon-152x152.png",
				"sizes": "152x152"
			}]
		}
	]
}

Registrar Trabajador de servicio

cree un archivo de secuencia de comandos register-service-worker.js y service-worker.js en la carpeta raíz.

El primero, register-service-worker.js es el archivo javascript que se ejecutará en el subproceso principal que puede acceder a la API DOM. Pero service-worker.js es un script de trabajador de servicio que se ejecuta independientemente del subproceso principal y su vida útil también es breve. Se ejecuta cada vez que los eventos llaman a los trabajadores del servicio y se ejecutan hasta que finaliza el proceso.

Al verificar el archivo javascript del hilo principal, puede verificar si el trabajador del servicio está registrado en él. si no, puede registrar el script del trabajador del servicio (service-worker.js).

pegue el siguiente fragmento en register-service-worker.js:

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

Pegue el siguiente fragmento en 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.
});

No nos concentramos en cómo habilitar el caché para el soporte sin conexión. Solo hablamos de cómo convertir aplicaciones web a PWA.

Agregue el archivo de manifiesto y la secuencia de comandos en la etiqueta de cabecera de su página HTML.

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

Actualice la página después de agregar. Ahora puede instalar su aplicación como se muestra a continuación en Chrome móvil.

En la pantalla de inicio, se agrega la aplicación.

Si está utilizando WordPress. Intente usar el complemento de conversión de PWA existente. Para vueJS o reactJS, puede seguir el método anterior o usar los módulos PWA npm existentes para acelerar su desarrollo. Porque los módulos PWA npm ya están habilitados con almacenamiento en caché de soporte sin conexión, etc.

Habilitar notificación de inserción

Las notificaciones web push se envían al navegador para que nuestros usuarios participen/interactúen con nuestra aplicación con más frecuencia. Podemos habilitarlo usando

  • API de notificación: Sirve para configurar cómo se debe mostrar al usuario nuestra notificación push.
  • empujar API: Se utiliza para recibir mensajes de notificación enviados desde nuestro servidor al navegador.

El primer paso para habilitar las notificaciones automáticas en nuestra aplicación es verificar la API de notificaciones y obtener el permiso del usuario para mostrar una notificación. Para eso, copie y pegue el fragmento a continuación en su 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);
        });
    }
};

Si todo salió correctamente. Recibirás una notificación de la aplicación.

‘Notificación’ en la ventana nos dirá que la API de notificación es compatible con ese navegador. Notification.permission indicará que al usuario se le ha permitido mostrar la notificación. Si el usuario permitió nuestra aplicación, el valor será ‘otorgado’. si el usuario ha rechazado el valor será ‘bloqueado’.

Habilite Firebase Cloud Messaging y cree una suscripción

Ahora comienza la parte real. Para enviar notificaciones desde su servidor al usuario, necesitamos un punto final/suscripción único para cada usuario. Para eso, vamos a utilizar la mensajería en la nube de firebase.

Como primer paso, cree una cuenta de firebase visitando este enlace https://firebase.google.com/ y presione empezar.

  • Cree un nuevo proyecto con un nombre y presione continuar. Voy a crearlo con el nombre kirukiru.es.
  • En el siguiente paso, Google Analytics está habilitado de forma predeterminada. Puede alternar que no necesitamos eso ahora y presionar continuar. Puede habilitarlo más tarde en su consola Firebase si lo necesita.
  • Una vez que se crea el proyecto, se verá como se muestra a continuación.
  • Luego vaya a la configuración del proyecto y haga clic en mensajería en la nube y genere claves.

    De los pasos anteriores, tienes 3 claves.

    • clave del servidor del proyecto
    • Clave privada de certificados web push
    • Clave pública de certificados web push

    Ahora pegue el siguiente fragmento en 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();

    Pegue el siguiente fragmento en 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)
    });

    Ahora todo listo en el front-end. Al usar la suscripción, puede enviar notificaciones automáticas a su usuario cuando lo desee hasta que no se les nieguen los servicios automáticos.

    Empuje desde el backend de node.js

    Puedes usar el web-push módulo npm para hacerlo más fácil.

    Fragmento de ejemplo para enviar notificaciones push desde el servidor 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 kirukiru.es-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 });
        });

    El código anterior enviará una notificación automática a la suscripción. Se activará el evento push en el service-worker.

    Empuje desde el backend de PHP

    Para el backend de PHP, puede usar el web-push-php paquete compositor. Consulte el código de ejemplo para enviar notificaciones automáticas a continuación.

    <?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 kirukiru.es-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)
    );

    Conclusión

    Espero que esto le dé una idea sobre cómo convertir aplicaciones web a PWA. Puedes consultar el código fuente de este artículo. aquí y demuéstralo aquí. También probé la notificación push enviándola desde el backend con la ayuda de un código de ejemplo.