Integrando notificaciones push y tokens FCM en iOS: una guía práctica desde la experiencia real
Tras múltiples iteraciones, Enolisa logra integrar correctamente el flujo de notificaciones push en iOS con Firebase Cloud Messaging y APNs, consolidando un modelo estable y multiplataforma para mensajería y engagement.
Enolisa iOS: integración completa de notificaciones push con Firebase Cloud Messaging y APNs
Contexto y punto de partida
La integración de notificaciones push en iOS ha sido uno de los procesos más complejos dentro del desarrollo de Enolisa.
A diferencia de Android, donde Firebase Cloud Messaging (FCM) gestiona todo de forma directa, en iOS se requiere una conexión intermedia con el Apple Push Notification Service (APNs).
Este paso implica permisos del sistema, claves de autenticación y configuración nativa, y si se ejecuta fuera de orden, la app no llega a registrar el token.
Estructura técnica
El flujo final implementado en Enolisa se basa en una arquitectura clara y escalonada:
| Etapa | Componente | Descripción |
|---|---|---|
| 1️⃣ | Apple Developer | Activación de Push Notifications y creación de claves APNs (.p8) para Sandbox y Production. |
| 2️⃣ | Firebase Console | Subida de las dos claves .p8, asociadas al mismo Bundle ID, para entornos Development y Production. |
| 3️⃣ | Xcode | Activación de las capabilities Push Notifications y Background Modes → Remote notifications. |
| 4️⃣ | Flutter | Inicialización correcta de flutter_local_notifications (solo para notificaciones locales) y firebase_messaging (para push). |
| 5️⃣ | Firestore | Persistencia de tokens FCM por usuario, permitiendo trazabilidad completa y refresco dinámico. |
Configuración en Apple Developer y Firebase
Claves APNs (.p8)
- Se generaron dos claves independientes:
- Una para Sandbox (Development).
- Otra para Production.
- Ambas se subieron a Firebase Console → Cloud Messaging, vinculadas al mismo Team ID y Bundle ID.
Configuración en Xcode
- Target Runner → pestaña Signing & Capabilities:
- Se añadieron Push Notifications y Background Modes → Remote notifications.
- En
Info.plist:1 2 3 4 5 6
<key>FirebaseAppDelegateProxyEnabled</key> <true/> <key>UIBackgroundModes</key> <array> <string>remote-notification</string> </array>
Código y flujo en Flutter
Inicialización de notificaciones locales
Se mantiene la inicialización mínima de flutter_local_notifications:
1
2
3
4
5
6
7
8
9
10
11
12
final DarwinInitializationSettings iosInit = const DarwinInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
);
final InitializationSettings initSettings = InitializationSettings(
android: androidInit,
iOS: iosInit,
);
await flutterLocalNotificationsPlugin.initialize(initSettings);
Esto permite mostrar notificaciones locales en Enolisa sin interferir con el flujo de permisos del sistema.
Solicitud de permisos push
El punto crítico fue entender que el prompt oficial de iOS solo aparece cuando se llama a:
1
2
3
4
5
await FirebaseMessaging.instance.requestPermission(
alert: true,
badge: true,
sound: true,
);
Este método se conecta al framework nativo UserNotifications, creando automáticamente la entrada “Notificaciones” en los ajustes del sistema.
Para Android, se mantiene la integración con permission_handler:
1
2
3
if (Platform.isAndroid) {
final status = await Permission.notification.request();
}
Centralización de permisos y tokens
Toda la gestión se unificó en FcmTokenManager (fcm_sync.dart):
1
2
3
4
5
6
7
8
9
10
11
12
13
static Future<void> solicitarPermisosNotificaciones() async {
if (Platform.isIOS) {
final settings = await FirebaseMessaging.instance.requestPermission(
alert: true,
badge: true,
sound: true,
);
EnolisaErrorHandler.log("🔐 iOS push authStatus: ${settings.authorizationStatus}");
} else if (Platform.isAndroid) {
final status = await Permission.notification.request();
EnolisaErrorHandler.log("🔐 (Android) Notif status: $status");
}
}
El mismo módulo gestiona también el registro del token FCM y su almacenamiento en Firestore:
1
2
final token = await FirebaseMessaging.instance.getToken();
await _db.collection('diarios').doc(user.uid).set({'token': token});
Resultados
- ✅ El prompt de notificaciones aparece correctamente en iOS tras instalar la app.
- ✅ La sección Notificaciones figura en los ajustes del sistema.
- ✅ Se generan y sincronizan los tokens FCM con Firestore.
- ✅ Envíos de prueba desde Firebase Console llegan correctamente a los dispositivos reales.
Lecciones aprendidas
- El permiso real en iOS no lo gestiona
permission_handler, sinoFirebaseMessaging.requestPermission(). - Sin esa llamada, iOS nunca registra la app en APNs y no crea el menú de Notificaciones.
flutter_local_notificationssirve únicamente para mostrar notificaciones locales; no pide permisos.- Es recomendable esperar unos milisegundos antes de pedir
getToken()hasta que APNs devuelva su token. - Tener dos claves APNs (Sandbox + Production) evita problemas entre entornos.
Conclusión
El proceso fue largo, pero dejó una base sólida y documentada. Enolisa ya dispone de un flujo push completo, estable y multiplataforma, que permite comunicación proactiva y engagement sin depender de hacks ni permisos inconsistentes.
Cada token, cada notificación, y cada flujo ahora están completamente trazados, con un sistema capaz de crecer en complejidad sin perder control operativo.