Conecta las AWP y las IWA con extensiones de Chrome

Demián Renzulli
Demián Renzulli

Como desarrollador web, es una práctica recomendada diseñar tus aplicaciones con el modelo de seguridad de menor confianza posible, como una app web progresiva (AWP). Este enfoque maximiza tu alcance, minimiza la sobrecarga de seguridad que debes administrar y ofrece la mayor flexibilidad para desarrolladores y usuarios. Sin embargo, debido a que la Web está diseñada para ser segura de forma predeterminada, su modelo de seguridad conservador restringe naturalmente el acceso al sistema operativo y a ciertas APIs potentes del dispositivo.

Las apps web aisladas (IWA) resuelven este problema, ya que proporcionan un modelo de aplicación aislado, empaquetado, con versiones, firmado y de alta confianza creado sobre la plataforma web. Sin embargo, antes de dar el salto a una IWA, vale la pena considerar un paso más gradual: conectar tu AWP con una extensión de Chrome. Disponible en entornos ChromeOS administrados, como sesiones de usuario administradas, sesiones de invitado administradas (MGS) o modo kiosco, esta técnica permite que tu app use APIs de extensión de nivel inferior a través del paso de mensajes seguros. En el siguiente diagrama, se ilustra este enfoque progresivo: comenzar con una aplicación web estándar, agregar las capacidades para convertirse en una AWP instalable y, por último, explorar la ruta de la AWP y la extensión de Chrome para desbloquear APIs adicionales.

imagen
La ruta de mejora progresiva Cuando se vincula una AWP instalable con una extensión de Chrome complementaria, los desarrolladores pueden cerrar la brecha entre el entorno seguro de la Web y las funciones de nivel inferior del SO y del dispositivo.

Si tu aplicación requiere capacidades avanzadas que no están disponibles incluso con las APIs de la extensión de Chrome, como Controlled Frame o la API de Direct Sockets, migrar a una app web aislada (IWA) es el mejor camino a seguir. Sin embargo, si bien las IWA desbloquean nuevas y potentes funciones web, es posible que aún necesites APIs específicas a nivel del dispositivo que sean exclusivas de las extensiones de Chrome, como chrome.runtime.restart() para reiniciar un dispositivo ChromeOS en modo kiosco. Afortunadamente, puedes conectar una IWA a una extensión de Chrome con el mismo enfoque que una AWP. Esta técnica se explica en los siguientes pasos.

Implementación paso a paso

Implementa la extensión complementaria

Las extensiones se implementan a través de la Consola del administrador de Chrome. Según tu entorno de destino, configurarás esto en la sección correspondiente (por ejemplo, navega a Dispositivos > Chrome > Apps y extensiones > Kioscos para el modo kiosco o las pestañas respectivas para Usuarios y navegadores o Sesiones de invitado administradas). Puedes alojar la extensión por tu cuenta en un vínculo de acceso público o alojarla directamente en Chrome Web Store. Para obtener instrucciones más detalladas sobre la administración de extensiones, consulta la documentación oficial.

Implementa el paso de mensajes

Configuración de la extensión

Para recibir mensajes de tu app web y responderlos, expón una secuencia de comandos en segundo plano que escuche los mensajes que llegan del cliente (tu app web) y, luego, envíe esas solicitudes a una llamada a la API correspondiente. En el siguiente ejemplo, se envía una solicitud para reiniciar el dispositivo ChromeOS cuando la app web envía un objeto de mensaje personalizado que contiene un methodName de callRestart.

Background.js

// message handler - extension code
chrome.runtime.onMessageExternal.addListener(function (request, sender, sendResponse) {
  if (request.methodName == 'callRestart') {
    chrome.runtime.restart();
  }
});

El manifiesto de la extensión se puede configurar para permitir llamadas a funciones externas a la extensión con la clave externally_connectable⁠⁠, que especifica qué sitios y extensiones pueden llamar a métodos en la extensión. Puedes encontrar más información sobre las extensiones de Chrome y el manifiesto v3 en la documentación oficial⁠⁠.

Si te conectas desde una app web progresiva (AWP), enumerarás el dominio HTTPS estándar en el que se aloja tu app en el array de coincidencias. Este es un ejemplo de un manifiesto configurado para una AWP que se ejecuta en modo kiosco:

Manifest.json

{
  "manifest_version": 3,
  "name": "Restart your kiosk app",
  "version": "1.0",
  "description": "This restarts your ChromeOS device.",
  "background": {
    "service_worker": "background.js"
  },
  "externally_connectable": {
    "accepts_tls_channel_id": false,
    "matches": [
      "*://developer.chrome.com/*"
    ]
  }
}

Si te conectas desde una app web aislada (IWA), el mecanismo es exactamente el mismo, pero el esquema de URL cambia. Debido a que las IWA están empaquetadas de forma segura y no se ejecutan en servidores web estándar, usan su propio protocolo. Debes agregar el origen de la IWA con el esquema isolated-app://.

Manifest.json

{
  "manifest_version": 3,
  "name": "IWA Companion Extension",
  "version": "1.1",
  "description": "Companion extension for the IWA",
  "background": {
    "service_worker": "/scripts/background.js"
  },
  "externally_connectable": {
    "matches": [
      "isolated-app://*/*"
    ]
  }
}

Esta es la cantidad mínima de código que se requiere en una extensión para escuchar mensajes de una AWP o IWA.

Configuración de AWP y IWA

Para llamar a la extensión desde una app web, debes conocer su ID de extensión estático. Este ID se puede encontrar en la página chrome://extensions, que se muestra cuando instalas tu extensión de Chrome, o en Chrome Web Store después de que se sube la extensión. Esto permite que tu app web especifique la extensión exacta con la que se comunicará. Después de eso, llama a chrome.runtime.sendMessage⁠⁠ y pasa el ID de la extensión con un mensaje para enviarlo a la extensión.

const STATIC_EXTENSION_ID = 'abcdefghijklmnopqrstuvwxyz';
// found from chrome extensions page of chrome web store.
const callExtensionAPI = function (method) {
  chrome.runtime.sendMessage(STATIC_EXTENSION_ID, {
    methodName: method,
  });
};
callExtensionAPI('callRestart');

Para obtener más información sobre cómo conectar apps web a extensiones para el paso de mensajes, consulta la documentación de extensiones⁠⁠.

Demostración

Para ver esta implementación en acción, explora el repositorio de IWA Kitchen Sink. Este proyecto sirve como un entorno de pruebas integral para varias capacidades de IWA, con demostraciones de APIs de alta confianza como Direct Sockets y Controlled Frame. También proporciona un ejemplo completo y funcional de la conexión de IWA a la extensión de Chrome. El repositorio incluye una extensión complementaria de muestra y una interfaz web dedicada que muestra cómo usar el paso de mensajes seguros para activar métodos exclusivos de la extensión. Por ejemplo, puedes probar la recuperación de la información del perfil del usuario con la API de chrome.identity.getProfileUserInfo() directamente desde la app web aislada.

Conclusión

Conectar tus aplicaciones web a una extensión de Chrome ofrece una ruta segura y progresiva para desbloquear capacidades del dispositivo similares a las nativas. Cuando diseñes la arquitectura de tu app, ten en cuenta estos puntos clave:

  1. Comienza con la Web: Usa una AWP de forma predeterminada para obtener el mejor alcance y la menor sobrecarga de seguridad.
  2. Cierra la brecha con las extensiones: Para las funciones profundamente integradas a nivel del SO (como el reinicio del dispositivo en modo kiosco), implementa una extensión de Chrome complementaria y conéctala a tu aplicación mediante el paso de mensajes seguros.
  3. Actualiza a IWA solo si es necesario: Usa apps web aisladas cuando necesites APIs de alta confianza como Direct Sockets, Controlled Frame o cualquiera de las otras APIs exclusivas de IWA.