Notificaciones push en una web: el iPhone y los husos horarios
Cómo envía el hub avisos al móvil sin ser una app de la tienda, por qué en el iPhone hay que añadirlo a la pantalla de inicio y los tres problemas reales que hubo que resolver: duplicados, cambios de hora y avisos que llegan tarde.
Unos amigos que probaron el hub pidieron lo obvio: que el calendario avisara en el móvil antes de una cita. El hub no es una app de la App Store ni de Google Play, es una web. Aun así puede enviar notificaciones que aparecen en el teléfono igual que las de cualquier otra app. Esto es lo que hay detrás y lo que costó que funcionara bien.
Cómo puede una web enviar notificaciones
El mecanismo se llama Web Push y tiene tres partes:
- Un service worker: un pequeño programa que el navegador guarda y que puede despertarse aunque la web no esté abierta. Es quien recibe el aviso y lo muestra.
- Una suscripción: cuando aceptas los avisos, el navegador genera una dirección única para ese dispositivo, alojada en el servicio de notificaciones de su fabricante (Apple, Google o Mozilla), y unas claves de cifrado.
- El servidor, que guarda esa suscripción y, cuando toca avisar, envía el mensaje cifrado a esa dirección, firmado con un par de claves propio para demostrar quién lo manda.
El fabricante del navegador solo transporta un paquete cifrado: no puede leer el contenido del aviso. Y la suscripción es por dispositivo, por eso hay que activar los avisos en cada uno.
La particularidad del iPhone
En Android y en el ordenador basta con pulsar «activar avisos» y aceptar. En el iPhone no. Apple permite las notificaciones web desde iOS 16.4, pero solo para las webs añadidas a la pantalla de inicio. Abierta en Safari como una pestaña más, la función sencillamente no existe.
El primer síntoma fue desconcertante: en el iPhone el botón de activar avisos no aparecía y no había ningún error. La solución técnica no era posible, así que la solución fue explicarlo: si el hub detecta que está en un iPhone y no se ha abierto desde el icono de la pantalla de inicio, muestra las instrucciones en lugar del botón. El paso a paso para usuarios está en avisos en el iPhone, Android y el ordenador.
Decidir cuándo toca avisar
Para las novedades de un grupo es fácil: alguien añade un producto y en ese momento se avisa a los demás. Los recordatorios del calendario son otra cosa. Nadie hace nada a las 17:00 del viernes; tiene que haber algo mirando el reloj.
Ese algo es un proceso que se ejecuta cada minuto y se pregunta: ¿qué recordatorios tienen su aviso dentro de este minuto? Parece trivial. No lo fue por tres motivos.
Problema 1: las horas son locales
Una cita a las 17:30 es a las 17:30 de España, y el servidor trabaja en hora universal. La diferencia es de una hora en invierno y de dos en verano, y cambia dos domingos al año.
Guardar la cita como «fecha y hora local» y convertirla al comprobar suena simple, pero tiene una trampa: para saber cuánto hay que restar a las 17:30 del 25 de octubre necesitas saber si ese momento está en horario de verano o de invierno, y eso depende del propio resultado. Lo resolvimos calculando en dos pasadas, primero con una estimación y después corrigiendo con la diferencia real de ese instante, y con pruebas específicas para los dos días de cambio de hora del año. Sin esas pruebas, el fallo habría aparecido una madrugada de domingo.
Problema 2: no avisar dos veces
Si el proceso se reinicia justo en el minuto de un aviso, o por algún motivo hay dos copias funcionando a la vez, el usuario recibe el mismo aviso repetido. La solución es reservar antes de enviar: el proceso intenta anotar en la base de datos «el aviso de esta cita para este día ya está cogido». La base de datos garantiza que esa anotación solo puede hacerse una vez. Quien consigue anotarla, envía. Quien llega después, no hace nada.
El orden importa: primero se reserva y después se envía. Al revés, un fallo entre los dos pasos produciría un duplicado. Así, en el peor caso un aviso se pierde, pero nunca se repite.
Problema 3: los avisos que llegan tarde
Si el servidor está parado diez minutos por una actualización, los avisos de esos diez minutos se enviarán al volver, con un pequeño retraso. ¿Y si estuvo parado cinco horas? Recibir a las diez de la noche el aviso de una cita de las cinco no ayuda a nadie. Pusimos una ventana de quince minutos: lo que se retrasa menos que eso se envía; lo que se retrasa más se da por perdido.
Las citas que se repiten
Una cita semanal no son cincuenta y dos filas en la base de datos: es una sola, con su regla de repetición. El proceso calcula si la cita «cae» en ayer, hoy o mañana (mañana, por los avisos del día anterior; ayer, por el cambio de día entre horas locales y universales) y trata cada fecha como un aviso independiente, con su propia reserva.
Limpieza
Las suscripciones caducan: alguien desinstala el icono, borra los datos del navegador o cambia de móvil. Cuando eso pasa, el servicio del fabricante responde que esa dirección ya no existe, y el hub la borra. Si no se hiciera, la lista de suscripciones crecería con direcciones muertas.
Qué nos llevamos
- Una web puede avisar en el móvil tan bien como una app instalada, pero en el iPhone el usuario tiene que dar un paso que no es evidente. Hay que explicárselo dentro de la propia pantalla.
- Lo difícil de un recordatorio no es enviarlo: es enviarlo una sola vez, a su hora local, también el día que cambia la hora.
- Las fechas y las horas merecen pruebas propias. Es el tipo de código que parece correcto durante meses y falla dos días al año.