Notification Extension es un mecanismo de iOS que permite modificar el contenido y la apariencia de las notificaciones push antes de mostrarlas al usuario. Las extensiones funcionan del lado del sistema operativo en un proceso separado: UNNotificationServiceExtension procesa el contenido entrante, mientras que UNNotificationContentExtension gestiona la interfaz. Según Apple Developer Documentation, 2026, la Service Extension dispone de hasta 30 segundos para realizar tareas antes de que se muestre la notificación. Esta limitación es crítica al descargar archivos adjuntos o descifrar datos.
Puntos clave
Notification Extension es un componente de software de iOS que amplía el comportamiento estándar de las notificaciones push añadiendo la capacidad de modificar contenido y personalizar la interfaz. A diferencia de las notificaciones normales que el sistema muestra en un formato estándar, las extensiones permiten al desarrollador influir en el contenido antes de mostrarlo y crear una interfaz de usuario única.
Apple proporciona dos tipos de Notification Extension para diferentes propósitos: UNNotificationServiceExtension se encarga del procesamiento del payload entrante, mientras que UNNotificationContentExtension gestiona la visualización. Service Extension se ejecuta antes de que se muestre la notificación y tiene un tiempo de ejecución limitado — hasta 30 segundos según Apple Developer Documentation. Content Extension se activa después de que el usuario interactúa con la notificación y muestra una vista personalizada.
Una notificación push estándar de iOS es mostrada automáticamente por el sistema basándose en los campos alert, title y subtitle del payload JSON. Notification Extension intercepta el control: Service Extension recibe el payload bruto, lo modifica y lo pasa al sistema para su visualización. Content Extension reemplaza el banner estándar por una interfaz personalizada con cualquier elemento de control.
Cuando el dispositivo recibe una notificación push con la clave mutable-content: 1, el sistema inicia Service Extension en un proceso separado. El proceso de la extensión está aislado de la aplicación principal y tiene su propio sandbox con un límite de memoria de 50 MB. Tras completar el procesamiento, la extensión llama al completion handler, pasando el UNNotificationContent modificado al sistema para su visualización.
UNNotificationServiceExtension es la herramienta principal para modificar programáticamente las notificaciones push antes de mostrarlas al usuario. La extensión se activa automáticamente al recibir una notificación cuyo payload tiene el flag mutable-content: 1 activado. En 30 segundos, la extensión puede descargar un archivo adjunto multimedia, cambiar texto, descifrar datos cifrados o enriquecer el contenido.
La extensión implementa dos métodos clave del protocolo UNNotificationServiceExtension. El método didReceive recibe la solicitud entrante con el UNNotificationRequest bruto y permite la modificación a través del completion handler con un nuevo UNNotificationContent. El método serviceExtensionTimeWillExpire es llamado por el sistema un segundo antes del tiempo de espera — en él debes completar el procesamiento y pasar el resultado actual (posiblemente parcial).
Considera un escenario donde el servidor envía un push con una URL de imagen en un campo personalizado. Service Extension descarga esta imagen por red, crea un UNNotificationAttachment y lo añade al contenido. UNNotificationAttachment acepta un archivo local de imagen, video o audio y lo copia automáticamente al sandbox de la extensión. Tras crear el attachment, la extensión pasa el contenido actualizado al sistema.
class NotificationService: UNNotificationServiceExtension {
override func didReceive(_ request: UNNotificationRequest,
withContentHandler contentHandler:
@escaping (UNNotificationContent) -> Void) {
let userInfo = request.content.userInfo
guard let imageURL = URL(string: userInfo["image-url"] as! String)
else { contentHandler(request.content); return }
let attachment = try! UNNotificationAttachment(
identifier: "image", url: imageURL,
options: [UNNotificationAttachmentOptionsTypeHintKey: "jpg"])
let modifiedContent = request.content.mutableCopy()
as! UNMutableNotificationContent
modifiedContent.attachments = [attachment]
contentHandler(modifiedContent)
}
override func serviceExtensionTimeWillExpire() {
contentHandler?(bestAttemptContent ?? request.content)
}
}
Cuando se envían notificaciones con los mismos archivos adjuntos con frecuencia, se recomienda almacenar en caché los archivos descargados en el dispositivo. FileManager proporciona acceso al directorio de caché de la extensión, que persiste entre ejecuciones. Esto reduce el tiempo de procesamiento de notificaciones posteriores y disminuye la carga de red. Según Apple, el almacenamiento en caché puede reducir el tiempo de procesamiento a 2–5 segundos en lugar de una descarga completa.
UNNotificationContentExtension permite reemplazar el banner estándar de notificación por una interfaz personalizada creada en Interface Builder o SwiftUI. La extensión se activa cuando el usuario realiza una acción sobre la notificación: tocar, deslizar hacia abajo o 3D Touch. Content Extension recibe el contenido ya procesado por Service Extension y lo muestra en una vista personalizada.
Cada Content Extension se vincula a una o más categorías de notificación a través de Info.plist. La categoría se define en el servidor mediante el campo category del payload APNS. El sistema selecciona automáticamente la extensión adecuada según la categoría de la notificación recibida. La interfaz se construye mediante storyboard usando componentes UIKit estándar o SwiftUI View.
Content Extension admite botones personalizados y manejadores de toque definidos en UNNotificationAction. UNNotificationAction se crea en la etapa de registro de categoría y puede admitir entrada de texto mediante UNTextInputNotificationAction. Cuando el usuario pulsa un botón, la extensión recibe el callback didReceive con el identificador de acción y puede ejecutar la lógica correspondiente — abrir una URL, enviar una solicitud al servidor o actualizar la interfaz.
Content Extension se ejecuta en un proceso aislado con su propio ciclo de ejecución y un límite de memoria de aproximadamente 50 MB. El rendimiento de la extensión es crítico porque el watchdog del sistema termina el proceso cuando se exceden los límites. Se recomienda evitar cálculos pesados, carga de imágenes grandes y solicitudes de red prolongadas dentro de Content Extension.
UNNotificationAttachment es un objeto que añade un archivo multimedia a una notificación push: imagen, video, audio o GIF. El attachment se crea a partir de una URL de archivo local que debe residir en el sandbox de la extensión. El tamaño máximo del attachment no debe superar los 10 MB, de lo contrario el sistema lo rechazará al crearlo.
Apple admite un conjunto limitado de formatos para attachments multimedia. Imágenes — JPEG, PNG, GIF (incluyendo animados), TIFF. Video — MPEG, MP4, MOV con una duración máxima de 30 segundos. Audio — MP3, AAC, WAV, CAF. Para cada formato se puede especificar el tipo mediante UNNotificationAttachmentOptionsTypeHintKey, lo que ayuda al sistema a procesar el archivo correctamente.
Como el payload push solo contiene una URL, no el archivo en sí, la descarga del attachment debe realizarse dentro de Service Extension. El tiempo máximo de descarga está limitado a 30 segundos, por lo que se recomienda usar URLSession con configuraciones mínimas y deshabilitar la descarga en señal débil. Si el attachment no se carga a tiempo, la notificación se muestra sin contenido multimedia — este es el comportamiento predeterminado del sistema.
Veamos un ejemplo completo de Notification Extension que descarga una imagen, la guarda y la añade a la notificación. NotificationService hereda de UNNotificationServiceExtension y sobrescribe el método didReceive. El ejemplo muestra el manejo de campos opcionales, la creación del attachment y la llamada al completion handler con el contenido modificado.
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler:
@escaping (UNNotificationContent) -> Void
) {
self.contentHandler = contentHandler
self.bestAttemptContent =
(request.content.mutableCopy()
as! UNMutableNotificationContent)
guard let attachmentURLString =
bestAttemptContent?.userInfo["attachment-url"] as? String,
let url = URL(string: attachmentURLString)
else {
contentHandler(request.content)
return
}
URLSession.shared.downloadTask(with: url) {
[weak self] localURL, _, error in
guard let localURL = localURL, error == nil
else {
contentHandler(request.content)
return
}
let attachment = try! UNNotificationAttachment(
identifier: "media", url: localURL)
self?.bestAttemptContent?.attachments = [attachment]
contentHandler(self?.bestAttemptContent
?? request.content)
}.resume()
}
override func serviceExtensionTimeWillExpire() {
if let content = bestAttemptContent {
contentHandler?(content)
}
}
}
Para que la extensión funcione correctamente, es necesario registrar las categorías de notificación en Info.plist. La clave NSExtensionPointIdentifier se establece como com.apple.usernotifications.service para Service Extension o com.apple.usernotifications.content para Content Extension. Las categorías se definen en AppDelegate al iniciar la aplicación mediante UNUserNotificationCenter, y la extensión solo se activa para notificaciones con una categoría coincidente en el payload.
Preguntas frecuentes
Service Extension modifica el contenido antes de mostrar la notificación — añade medios, cambia texto, descifra datos. Content Extension reemplaza la interfaz de la notificación por una personalizada tras la interacción del usuario. Service Extension funciona antes de la visualización, Content Extension después.
El sistema asigna 30 segundos para la ejecución de código en didReceive. Si el procesamiento no se completa dentro de este tiempo, se llama a serviceExtensionTimeWillExpire, donde debes pasar el resultado actual. Se recomienda mantenerse dentro de 10–15 segundos considerando la descarga de attachments.
Sí, SwiftUI es compatible con Content Extension desde iOS 16. La Vista se envuelve en un UIHostingController y se añade al storyboard. Sin embargo, debido a los límites de memoria, se recomienda usar SwiftUI solo para interfaces simples con un número mínimo de elementos.
En caso de error de descarga o tiempo de espera, simplemente llama al completion handler con el contenido original sin attachment. El sistema mostrará la notificación en formato estándar sin medios. Registra los errores mediante OSLog para diagnóstico, pero no bloquees la visualización de la notificación.
La extensión se ejecuta en un proceso aislado con un límite de aproximadamente 50 MB. Al superarlo, el sistema termina el proceso mediante watchdog. Evita cargar archivos grandes, almacenar imágenes en memoria y fugas al trabajar con URLSession.
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