Notification Service Extension é uma extensão do iOS que intercepta uma notificação push imediatamente após o recebimento, mas antes de ser exibida ao usuário. A extensão pode descriptografar um payload criptografado, baixar e anexar arquivos de mídia e alterar o texto ou título da notificação em tempo real. De acordo com a documentação para desenvolvedores da Apple (2025), para ativar a extensão, o servidor deve enviar a chave mutable-content:1 nos atributos da notificação — esta é a única condição para executar o UNNotificationServiceExtension.
Pontos principais
Notification Service Extension é uma extensão de aplicativo no iOS que intercepta uma notificação push recebida no dispositivo e permite modificar seu conteúdo antes que o usuário a veja. Este é o único tipo de extensão de notificação que trabalha com o conteúdo, não com a exibição.
A principal diferença da Notification Content Extension: a Service Extension funciona antes da notificação ser exibida e pode alterar o título, corpo, arquivo de som e anexos. A Content Extension funciona após a exibição e gerencia apenas a apresentação visual da notificação pronta. Essas duas extensões podem trabalhar juntas: a Service Extension baixa uma imagem e a Content Extension a exibe em uma interface personalizada.
A extensão é ativada automaticamente ao receber uma notificação push com o atributo mutable-content:1 no dicionário aps. O iOS inicia a extensão em segundo plano, passa a UNNotificationRequest original e aguarda uma versão modificada para exibir.
UNNotificationServiceExtension recebe a UNNotificationRequest completa com o conteúdo original. A extensão pode modificar qualquer campo do UNNotificationContent: title, subtitle, body, userInfo, attachments e sound. As alterações são aplicadas antes da notificação ser exibida.
Descriptografia de conteúdo — se uma notificação push contém um payload criptografado, a extensão o descriptografa antes da exibição. Download de mídia — anexar uma imagem ou vídeo à notificação. Localização — adaptar o texto da notificação às configurações regionais do dispositivo. Enriquecimento de dados — adicionar informações adicionais do armazenamento local ou cache.
Segundo a Apple, o cenário mais comum entre os aplicativos é o download de imagens para notificações de mídia enriquecida. O servidor envia uma URL de imagem no payload, a extensão baixa para um diretório temporário e cria um UNNotificationAttachment, que o sistema exibe em uma interface padrão ou personalizada.
A extensão pode reescrever completamente o texto da notificação, substituir o título ou adicionar um subtítulo. Por exemplo, um aplicativo de mensagens pode receber uma notificação criptografada, descriptografá-la na extensão e exibir texto legível. Ou um aplicativo de notícias pode adicionar uma categoria de notícia ao subtítulo antes da exibição.
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 é a classe base da qual a Service Extension herda. A classe define dois métodos do ciclo de vida: didReceive(_:withContentHandler:) — o método principal de processamento, e serviceExtensionTimeWillExpire() — o manipulador de tempo limite.
didReceive(_:withContentHandler:) é chamado quando uma notificação é recebida. A extensão recebe uma UNNotificationRequest e um closure contentHandler, que deve ser chamado com o UNMutableNotificationContent modificado. A extensão é obrigada a chamar contentHandler — se não o fizer, o iOS exibirá a notificação original após o término do tempo limite.
Importante: a extensão só pode processar uma notificação por vez. Se várias notificações chegarem simultaneamente, o iOS cria instâncias separadas da extensão para cada uma. Não é possível usar estado global para processamento sequencial.
serviceExtensionTimeWillExpire() é chamado pelo sistema quando o tempo de execução restante está prestes a expirar. Neste método, você deve chamar imediatamente contentHandler com qualquer conteúdo que estiver pronto naquele momento — mesmo que o arquivo de mídia não tenha terminado de baixar. Se você não chamar contentHandler neste método, o iOS exibirá a notificação original.
Recomenda-se salvar conteúdo minimamente aceitável neste método — por exemplo, uma notificação com texto e título, mas sem imagem cujo download não foi concluído a tempo.
UNNotificationAttachment é um objeto criado pela extensão para anexar um arquivo de mídia à notificação. A extensão baixa o arquivo da rede, salva em um diretório temporário e cria um UNNotificationAttachment especificando o tipo de conteúdo.
UNNotificationAttachment é criado usando o inicializador init(identifier:url:options:). A URL deve apontar para um arquivo local no diretório temporário acessível à extensão. Após a criação, o anexo é adicionado ao array de attachments do UNMutableNotificationContent.
A Apple recomenda usar URLSession com configuração em segundo plano para download — ao usar URLSession padrão, o download bloqueia a thread e consome tempo do limite de 30 segundos. A URLSession em segundo plano continua o download mesmo quando a extensão é encerrada, e o resultado pode ser usado na próxima inicialização.
Se o servidor enviar uma notificação criptografada, a extensão deve descriptografar o payload antes de chamar contentHandler. A descriptografia geralmente envolve solicitar uma chave do Keychain ou App Group, descriptografar via CommonCrypto e substituir o body ou userInfo da notificação. Em caso de erro de descriptografia, você deve chamar contentHandler com o conteúdo original — para que o usuário pelo menos veja que uma notificação chegou, mesmo que ilegível.
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 prazos rigorosos. O iOS aloca um tempo de execução fixo — aproximadamente 30 segundos desde a ativação. Se a extensão não chamou contentHandler dentro deste tempo, o sistema encerra forçadamente o processo e exibe a notificação original sem alterações.
Recomenda-se implementar um fallback de vários níveis: primeiro tentar baixar a mídia, em caso de sucesso chamar contentHandler com conteúdo completo; em caso de falha chamar contentHandler com texto, mas sem mídia; em caso de erro crítico, passar o conteúdo original. Esta abordagem garante que o usuário sempre veja uma notificação, não uma tela em branco.
Segundo a Apple, a causa mais comum de tempos limite é o download de arquivos de mídia grandes em conexão lenta. Para reduzir o risco, recomenda-se otimizar o tamanho das imagens no servidor — enviar prévias de até 300 KB em vez de resolução total. Imagens em tamanho real devem ser baixadas ao abrir o aplicativo.
Para rastrear tempos limite e erros da extensão, você pode usar os_log para registrar mensagens de diagnóstico no Unified Logging System. Embora o registro direto em arquivo na extensão seja difícil, o os_log permite análise de desempenho através do Console.app no dispositivo do desenvolvedor. A Apple recomenda adicionar métricas em cada chamada didReceive — tempo de download, tamanho do arquivo, resultado da operação.
override func serviceExtensionTimeWillExpire() {
let fallback = bestEffortContent as?
UNMutableNotificationContent
?? request.content.mutableCopy()
as! UNMutableNotificationContent
contentHandler(fallback)
}
Perguntas frequentes
O servidor adiciona a chave mutable-content:1 ao dicionário aps da notificação push. Sem este parâmetro, o sistema ignora a extensão e exibe a notificação padrão.
Não. mutable-content:1 é uma condição obrigatória para ativar a Service Extension. Se a chave estiver ausente ou definida como 0, a notificação é exibida sem chamar a extensão.
O iOS encerra forçadamente a extensão e exibe a notificação original sem alterações. Para evitar isso, implemente serviceExtensionTimeWillExpire() com conteúdo minimamente aceitável.
Através de App Group (UserDefaults ou arquivo compartilhado) ou Keychain com acesso compartilhado entre o aplicativo e a extensão. Passar chaves diretamente no payload da notificação não é seguro.
Até 4 anexos por notificação, cada um até 50 MB. O tamanho total dos anexos afeta o tempo de download — quanto mais arquivos, maior o risco de tempo limite.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também