Notification Service Extension é uma extensão do iOS que intercepta uma notificação push antes de ser exibida ao usuário e permite modificar o conteúdo. A extensão pode descriptografar dados criptografados, baixar anexos de mídia, alterar texto ou adicionar campos personalizados. De acordo com Apple Developer, 2025, o Notification Service Extension tem até 30 segundos para concluir a tarefa em segundo plano.
Principais pontos
Notification Service Extension é uma extensão de aplicativo no iOS que é executada antes da exibição de uma notificação push. Permite que o servidor envie um payload mínimo enquanto a extensão o enriquece com conteúdo: baixar imagens, descriptografar dados, substituir texto. O usuário vê a notificação já processada.
Quando o iOS recebe uma notificação push, o sistema verifica se existe uma extensão para o aplicativo. Se a extensão estiver registrada, o iOS a inicia em um processo em segundo plano e passa o conteúdo da notificação através do método didReceive(_:withContentHandler:). A extensão processa o conteúdo e chama contentHandler com o conteúdo modificado. Se a extensão não concluir em 30 segundos, o sistema exibe a notificação original.
Service Extension é necessário em cenários onde o conteúdo da notificação requer processamento no dispositivo. Comunicações seguras: o servidor envia um payload criptografado, a extensão o descriptografa localmente. Notificações de mídia ricas: o servidor envia uma URL de imagem, a extensão baixa e anexa. Localização dinâmica: a extensão substitui o texto no idioma do dispositivo.
| Cenário | Sem extensão | Com extensão |
|---|---|---|
| Imagem | Não suportado | Baixada e exibida |
| Criptografia | Servidor armazena a chave | Descriptografia no dispositivo |
| Texto | Fixo no servidor | Substituição dinâmica |
| Validação | Não verificada | Notificações maliciosas canceladas |
Notification Service Extension funciona em um ambiente limitado. O tempo máximo de execução é de 30 segundos. A extensão não tem acesso ao armazenamento principal do aplicativo (exceto App Group). O tamanho da extensão é limitado a 50 MB. Quando o tempo é excedido, o sistema chama contentHandler com o conteúdo original e todas as alterações são perdidas.
No Xcode, o Notification Service Extension é adicionado criando um novo target do tipo Notification Service Extension. O Xcode gera uma classe de modelo NotificationService herdando de UNNotificationServiceExtension, com dois métodos: didReceive e serviceExtensionTimeWillExpire.
No Xcode, selecione File → New → Target → Notification Service Extension. Insira um nome (por exemplo, PushNotificationService) e escolha a linguagem Swift. Certifique-se de que o target seja adicionado ao aplicativo principal e tenha a assinatura correta. Após a criação, a classe NotificationService.swift com uma implementação básica será gerada.
O Info.plist da extensão contém a chave NSExtension com as subchaves NSExtensionPointIdentifier (com.apple.usernotifications.service) e NSExtensionPrincipalClass (o nome do seu controlador). Adicionalmente, NSExtensionAttributes podem ser especificados com regras de ativação da extensão. O Xcode gera essas configurações automaticamente.
A implementação básica sobrescreve didReceive, modifica o conteúdo da notificação e chama contentHandler. Se o processamento levar muito tempo, serviceExtensionTimeWillExpire é chamado, onde você precisa concluir o trabalho com o estado atual.
import UserNotifications
class NotificationService: UNNotificationServiceExtension {
var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
request: UNNotificationRequest,
withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
contentHandler = handler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
if let bestAttemptContent = bestAttemptContent {
bestAttemptContent.title = "[Processado] \(bestAttemptContent.title)"
contentHandler?(bestAttemptContent)
}
}
override func serviceExtensionTimeWillExpire() {
if let contentHandler = contentHandler,
let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}
}
Um dos principais usos do Service Extension é descriptografar o conteúdo da notificação no dispositivo. O servidor envia um payload criptografado e a extensão o descriptografa usando uma chave armazenada no Keychain ou App Group. Isso garante que o conteúdo não possa ser interceptado durante a transmissão.
O servidor criptografa o corpo da notificação usando uma chave simétrica (AES-256). A chave de criptografia é pré-acordada entre o cliente e o servidor. A extensão recebe a string criptografada no campo data do payload, a descriptografa e a substitui nos campos da notificação. A chave do usuário pode ser obtida do Keychain após a autenticação.
override func didReceive(
request: UNNotificationRequest,
withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
guard let content = request.content.mutableCopy()
as? UNMutableNotificationContent else {
handler(request.content)
return
}
guard let encryptedData = content.userInfo["encrypted_data"]
as? String else {
handler(content)
return
}
let decrypted = CryptoService.decrypt(encryptedData)
content.body = decrypted.body
content.title = decrypted.title
handler(content)
}
A chave de descriptografia não deve ser armazenada no código da extensão ou no NSUserDefaults. Use o iOS Keychain com acesso via App Group para que tanto o aplicativo quanto a extensão possam ler a chave. Use o Security.framework com o algoritmo AES-256-GCM para geração de chaves no cliente.
O uso mais comum do Notification Service Extension é baixar imagens, GIFs e vídeos para exibição na notificação. O servidor envia uma URL de arquivo de mídia e a extensão o baixa, salva em um diretório temporário e cria um UNNotificationAttachment.
A extensão recebe a URL da imagem do campo payload da notificação. Usando URLSession, a extensão baixa o arquivo para um diretório temporário. Após a conclusão do download, um UNNotificationAttachment com a URL local é criado. O anexo é passado para o conteúdo modificado. O iOS automaticamente exibe a imagem na interface padrão ou em uma Notification Content Extension.
private func downloadAndAttachMedia(
content: UNMutableNotificationContent,
mediaUrl: String,
handler: @escaping (UNNotificationContent) -> Void
) {
guard let url = URL(string: mediaUrl) else {
handler(content)
return
}
let task = URLSession.shared.downloadTask(with: url) { localUrl, _, error in
guard let localUrl = localUrl, error == nil else {
handler(content)
return
}
let attachment = try? UNNotificationAttachment(
identifier: "media",
url: localUrl,
options: nil
)
if let attachment = attachment {
content.attachments = [attachment]
}
handler(content)
}
task.resume()
}
O iOS suporta os seguintes formatos para exibição em notificações: JPEG, PNG, GIF (estáticos), vídeo MPEG-4 até 50 MB. Para arquivos de áudio, MP3, AAC e ALAC são suportados. Importante: todos os arquivos de mídia devem ser baixados dentro do limite de 30 segundos. Para arquivos grandes, recomenda-se o corte no servidor ou carregamento progressivo.
Gerenciar o limite de 30 segundos é uma tarefa chave ao desenvolver o Notification Service Extension. Se a extensão não concluir o processamento a tempo, o sistema chama serviceExtensionTimeWillExpire e exibe o conteúdo original. Cenários de fallback devem ser fornecidos para cada tipo de processamento.
Divida as tarefas por prioridade. Execute primeiro as modificações críticas (descriptografia, localização básica). Melhorias opcionais (download de imagens, enriquecimento de texto) vêm em segundo lugar. Use URLSession com timeouts para requisições de rede para evitar gastar todo o limite em uma única operação.
Se o download da imagem falhar ou a descriptografia do payload retornar um erro, a extensão deve chamar contentHandler com o conteúdo original. Nunca termine a extensão sem chamar contentHandler — isso leva à perda da notificação. Um fallback seguro deve sempre ser previsto no código da extensão.
override func didReceive(
request: UNNotificationRequest,
withContentHandler handler: @escaping (UNNotificationContent) -> Void
) {
let content = (request.content.mutableCopy()
as? UNMutableNotificationContent) ?? request.content
// Tarefa crítica: descriptografia
var decryptedContent = tryDecryptPayload(content)
// Tarefa opcional: mídia
guard let mediaUrl = decryptedContent.userInfo["media_url"]
as? String else {
handler(decryptedContent)
return
}
downloadAndAttachMedia(
content: decryptedContent,
mediaUrl: mediaUrl,
handler: handler
)
}
Para testar o Notification Service Extension, use o Xcode: selecione o target da extensão, execute no simulador e envie uma notificação push via terminal ou Firebase Console. Registre cada etapa do processamento usando os_log — isso ajuda a diagnosticar problemas de tempo e download.
Perguntas frequentes
O sistema chama serviceExtensionTimeWillExpire, então exibe a notificação original sem alterações. Todos os arquivos baixados e modificações são descartados.
Sim, se você chamar contentHandler com conteúdo vazio (UNNotificationContent com campos vazios), a notificação não será exibida. Isso é usado para filtrar notificações de spam ou dados incorretos.
O token pode ser passado no userInfo do payload da notificação ou obtido do Keychain via App Group. Não é recomendado armazenar tokens no UserDefaults da extensão.
A extensão deve ser assinada com o mesmo certificado de desenvolvedor do aplicativo principal. Para produção, é necessário um certificado de produção com a capacidade Push Notifications ativada.
Conecte o dispositivo ao Xcode, selecione o target da extensão no esquema de execução e envie uma notificação push via Firebase Console. Os breakpoints na extensão funcionam da mesma forma que no aplicativo principal.
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