Explica la entrega de notificaciones push de punta a punta — FCM/APNs, el sistema operativo y tu app
Tu servidor nunca le habla al dispositivo — le habla al relay de Google o Apple, que mantiene un socket abierto para el cual tu app ni siquiera necesita estar corriendo.
APRENDE HACIENDOPon a prueba tu intuición3 pasos
Explica la entrega de notificaciones push de punta a punta — FCM/APNs, el sistema operativo y tu app
Usa los ejemplos y la explicación de la lección para comprobar tu idea.
Reflexión personal. No se envía a ningún servicio de IA.#El único hecho que explica todo lo demás
Tu backend nunca abre una conexión hacia un teléfono. No puede — los dispositivos se mueven entre redes, apagan su radio para ahorrar batería y están detrás de NAT sin una dirección estable a la cual llamar. Así que tanto Apple como Google resolvieron esto de la misma forma: el sistema operativo del dispositivo mantiene abierta una conexión persistente y de larga duración hacia un servicio relay (APNs para Apple, el servidor de conexión de FCM para Android), y el único trabajo de tu servidor es entregarle un mensaje a ese relay y confiar en que lo entregue. Por eso el push funciona incluso cuando el proceso de tu app no existe — el socket le pertenece al sistema operativo, no a ti.
#Conseguir un token antes de poder enviar nada
Antes de que tu servidor pueda apuntar a un dispositivo específico, el dispositivo tiene que registrarse. En iOS, la app llama a registerForRemoteNotifications(), lo cual le pide al sistema que establezca identidad con APNs, y el sistema responde con un device token. En Android, el SDK de FCM hace el trabajo equivalente por debajo y le entrega a tu app un token de registro de FCM. En ambos casos el flujo es el mismo: la app pide un token al sistema, el sistema habla con el servicio push para generarlo, la app lo recibe y la app lo envía a tu backend, donde queda asociado a un id de usuario. Ese token no es permanente — rota al reinstalar, al restaurar un backup en un dispositivo nuevo y periódicamente por otras razones — así que tu backend tiene que tratar "el envío falló, token inválido" como una respuesta normal y esperada, y eliminarlo en vez de reintentar para siempre.
#Qué envía realmente tu servidor
Un payload de push es pequeño a propósito — es una señal de despertar, no un canal de datos. Tanto la API HTTP v1 de FCM como la API HTTP/2 de APNs aceptan un payload dividido conceptualmente en una parte de notificación (título, cuerpo — el sistema puede renderizarlo por sí mismo sin despertar tu código) y una parte de datos (pares clave-valor arbitrarios que tu app interpreta). También configuras la prioridad (normal vs. alta/inmediata — la normal puede posponerse por Doze, la alta pide entrega pronta), un tiempo de vida para que un mensaje obsoleto expire en vez de llegar horas tarde, y en iOS una bandera de payload (content-available: 1) para un push "silencioso" pensado para despertar brevemente la app y hacer trabajo en segundo plano sin mostrarle nada al usuario.
#Los tres estados que lo cambian todo
El mismo mensaje se maneja de forma completamente distinta según qué esté haciendo tu app cuando llega, y esta es la parte que los entrevistadores realmente quieren escucharte razonar en voz alta.
Cuando la app está en primer plano, el sistema le entrega el payload directamente a tu código — en Android es FirebaseMessagingService.onMessageReceived, en iOS es el callback willPresent del UNUserNotificationCenterDelegate — y depende enteramente de tu app decidir si muestra un banner interno, actualiza un badge o no hace nada, porque el sistema no va a poner una notificación en la bandeja para algo que el usuario ya está mirando. Cuando la app está en segundo plano pero viva, el sistema renderiza la notificación de bandeja él mismo a partir de la parte "notification" del payload sin tocar tu código en absoluto; si el payload es un push silencioso/de datos, el sistema puede conceder una breve ventana de despertar para que tu app haga trabajo útil en segundo plano antes de que el usuario siquiera toque algo. Cuando la app está cerrada, el sistema sigue siendo dueño de la conexión persistente y sigue renderizando la notificación en bandeja — tu código ejecuta cero instrucciones hasta que el usuario la toca, lo cual arranca en frío la app con el payload de la notificación disponible para leer al iniciar.
#El modo de falla que todos terminan encontrando
Los push silenciosos y solo de datos usados para sincronizar contenido son lo que silenciosamente deja de funcionar en producción y confunde a cualquier ingeniero que no haya construido el camino del push él mismo. iOS impone tanto un presupuesto de tasa sobre los push silenciosos como, más importante aún, suspende la entrega en segundo plano a una app que el usuario cerró forzosamente deslizándola hacia afuera — desde la perspectiva del sistema, ese gesto es el usuario diciendo "deja de ejecutar esto," y lo toma literalmente hasta que el usuario vuelve a abrir la app. El modo Doze de Android de forma similar posterga los mensajes de FCM de prioridad normal hasta la próxima ventana de mantenimiento del dispositivo, aunque los mensajes de alta prioridad reciben una breve excepción. Nada de esto es un bug en tu integración — es ambas plataformas negándose a dejar que el push se convierta en una puerta trasera para que las apps corran indefinidamente en segundo plano, y significa que el push es fundamentalmente una señal de despertar de mejor esfuerzo, sin orden garantizado y con entrega al menos una vez, nunca un canal de entrega garantizada para datos que tu app no pueda volver a obtener de otra forma.