Notification Service Extension es una extensión de iOS que intercepta una notificación push inmediatamente después de recibirla pero antes de mostrarla al usuario. La extensión puede descifrar un payload cifrado, descargar y adjuntar archivos multimedia, y cambiar el texto o título de la notificación en tiempo real. Según la documentación para desarrolladores de Apple (2025), para activar la extensión el servidor debe enviar la clave mutable-content:1 en los atributos de la notificación — esta es la única condición para ejecutar UNNotificationServiceExtension.
Puntos clave
Notification Service Extension es una extensión de aplicación en iOS que intercepta una notificación push entrante en el lado del dispositivo y permite modificar su contenido antes de que el usuario la vea. Este es el único tipo de extensión de notificaciones que trabaja con el contenido y no con la visualización.
La diferencia clave con Notification Content Extension: Service Extension funciona antes de que se muestre la notificación y puede cambiar el título, cuerpo, archivo de sonido y adjuntos. Content Extension funciona después de mostrarla y solo gestiona la presentación visual de la notificación terminada. Estas dos extensiones pueden trabajar juntas: Service Extension descarga una imagen y Content Extension la muestra en una interfaz personalizada.
La extensión se activa automáticamente al recibir una notificación push con el atributo mutable-content:1 en el diccionario aps. iOS inicia la extensión en segundo plano, le pasa la UNNotificationRequest original y espera una versión modificada para mostrar.
UNNotificationServiceExtension recibe la UNNotificationRequest completa con el contenido original. La extensión puede modificar cualquier campo de UNNotificationContent: title, subtitle, body, userInfo, attachments y sound. Los cambios se aplican antes de que se muestre la notificación.
Descifrado de contenido — si una notificación push contiene un payload cifrado, la extensión lo descifra antes de mostrarlo. Descarga de medios — adjuntar una imagen o video a la notificación. Localización — adaptar el texto de la notificación a la configuración regional del dispositivo. Enriquecimiento de datos — agregar información adicional del almacenamiento local o caché.
Según Apple, el escenario más común entre las aplicaciones es la descarga de imágenes para notificaciones multimedia enriquecidas. El servidor envía una URL de imagen en el payload, la extensión la descarga a un directorio temporal y crea un UNNotificationAttachment, que el sistema muestra en una interfaz estándar o personalizada.
La extensión puede reescribir completamente el texto de la notificación, reemplazar el título o agregar un subtítulo. Por ejemplo, una aplicación de mensajería puede recibir una notificación cifrada, descifrarla en la extensión y mostrar texto legible. O una aplicación de noticias puede agregar una categoría de noticia al subtítulo antes de mostrarla.
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
let content = request.content.mutableCopy()
as! UNMutableNotificationContent
if let imageURL = content.userInfo["media-url"]
as? String {
downloadAndAttach(imageURL: imageURL,
content: content,
handler: contentHandler)
}
}
UNNotificationServiceExtension es la clase base de la que hereda Service Extension. La clase define dos métodos del ciclo de vida: didReceive(_:withContentHandler:) — el método principal de procesamiento, y serviceExtensionTimeWillExpire() — el controlador de tiempo de espera.
didReceive(_:withContentHandler:) se llama cuando se recibe una notificación. La extensión recibe una UNNotificationRequest y un cierre contentHandler, que debe llamarse con el UNMutableNotificationContent modificado. La extensión está obligada a llamar a contentHandler — si no lo hace, iOS mostrará la notificación original después de que expire el tiempo de espera.
Importante: la extensión solo puede procesar una notificación a la vez. Si llegan varias notificaciones simultáneamente, iOS crea instancias separadas de la extensión para cada una. No se puede usar estado global para procesamiento secuencial.
serviceExtensionTimeWillExpire() es llamado por el sistema cuando el tiempo de ejecución restante está a punto de expirar. En este método, debe llamar inmediatamente a contentHandler con el contenido que esté listo en ese momento — incluso si el archivo multimedia no ha terminado de descargarse. Si no llama a contentHandler en este método, iOS mostrará la notificación original.
Se recomienda guardar contenido mínimamente aceptable en este método — por ejemplo, una notificación con texto y título pero sin imagen cuya descarga no se completó a tiempo.
UNNotificationAttachment es un objeto creado por la extensión para adjuntar un archivo multimedia a la notificación. La extensión descarga el archivo de la red, lo guarda en un directorio temporal y crea un UNNotificationAttachment especificando el tipo de contenido.
UNNotificationAttachment se crea usando el inicializador init(identifier:url:options:). La URL debe apuntar a un archivo local en el directorio temporal accesible para la extensión. Después de la creación, el adjunto se agrega al array de attachments de UNMutableNotificationContent.
Apple recomienda usar URLSession con configuración en segundo plano para la descarga — al usar URLSession estándar, la descarga bloquea el hilo y consume tiempo del límite de 30 segundos. URLSession en segundo plano continúa la descarga incluso cuando la extensión termina, y el resultado puede usarse en el siguiente inicio.
Si el servidor envía una notificación cifrada, la extensión debe descifrar el payload antes de llamar a contentHandler. El descifrado generalmente implica solicitar una clave de Keychain o App Group, descifrar mediante CommonCrypto y reemplazar el body o userInfo de la notificación. En caso de error de descifrado, debe llamar a contentHandler con el contenido original — para que el usuario al menos vea que llegó una notificación, aunque sea ilegible.
func downloadAndAttach(
imageURL: String,
content: UNMutableNotificationContent,
handler: @escaping (UNNotificationContent) -> Void
) {
let task = URLSession.shared.dataTask(with:
URL(string: imageURL)!) { data, _, _ in
let url = FileManager.default
.temporaryDirectory
.appendingPathComponent("image.jpg")
try? data?.write(to: url)
let attachment = try? UNNotificationAttachment(
identifier: "image", url: url)
content.attachments = [attachment].compactMap { $0 }
handler(content)
}
task.resume()
}
Notification Service Extension opera dentro de plazos estrictos. iOS asigna un tiempo de ejecución fijo — aproximadamente 30 segundos desde la activación. Si la extensión no ha llamado a contentHandler dentro de este tiempo, el sistema termina forzosamente el proceso y muestra la notificación original sin cambios.
Se recomienda implementar un respaldo de múltiples niveles: primero intentar descargar el contenido multimedia, en caso de éxito llamar a contentHandler con el contenido completo; en caso de fallo llamar a contentHandler con texto pero sin multimedia; en caso de error crítico pasar el contenido original. Este enfoque garantiza que el usuario siempre vea una notificación y no una pantalla en blanco.
Según Apple, la causa más común de tiempos de espera es la descarga de archivos multimedia grandes con una conexión lenta. Para reducir el riesgo, se recomienda optimizar el tamaño de las imágenes en el servidor — enviar vistas previas de hasta 300 KB en lugar de resolución completa. Las imágenes de tamaño completo deben descargarse al abrir la aplicación.
Para rastrear tiempos de espera y errores de la extensión, puede usar os_log para registrar mensajes de diagnóstico en el Unified Logging System. Aunque el registro directo en archivos en la extensión es difícil, os_log permite analizar el rendimiento a través de Console.app en el dispositivo del desarrollador. Apple recomienda agregar métricas en cada llamada a didReceive — tiempo de descarga, tamaño del archivo, resultado de la operación.
override func serviceExtensionTimeWillExpire() {
let fallback = bestEffortContent as?
UNMutableNotificationContent
?? request.content.mutableCopy()
as! UNMutableNotificationContent
contentHandler(fallback)
}
Preguntas frecuentes
El servidor agrega la clave mutable-content:1 al diccionario aps de la notificación push. Sin este parámetro, el sistema ignora la extensión y muestra la notificación estándar.
No. mutable-content:1 es una condición obligatoria para activar Service Extension. Si la clave falta o está configurada en 0, la notificación se muestra sin llamar a la extensión.
iOS termina forzosamente la extensión y muestra la notificación original sin cambios. Para evitarlo, implemente serviceExtensionTimeWillExpire() con contenido mínimamente aceptable.
A través de App Group (UserDefaults o archivo compartido) o Keychain con acceso compartido entre la aplicación y la extensión. Pasar claves directamente en el payload de la notificación no es seguro.
Hasta 4 adjuntos por notificación, cada uno hasta 50 MB. El tamaño total de los adjuntos afecta el tiempo de descarga — cuantos más archivos, mayor el riesgo de tiempo de espera.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también