Notificações
Exiba notificações nativas do sistema com botões de ação e entrada de texto
Introdução
O Wails oferece um sistema completo de notificações multiplataforma para aplicações desktop. Esse serviço permite exibir notificações nativas do sistema, com suporte a:
- Notificações básicas com título, subtítulo e corpo
- Notificações interativas com botões de ação e respostas de texto
- Categorias de notificação reutilizáveis para ações
- Sons personalizados (padrão, silencioso ou nomeado)
- Anexos (imagens em todas as plataformas; áudio/vídeo no macOS)
- Agrupamento de notificações relacionadas por
ThreadID - Prioridade por meio de
InterruptionLevel(passive/active/timeSensitive/critical) - Entrega agendada (nativa no macOS; temporizador no processo no Windows e no Linux)
- Atualização de uma notificação em andamento por ID
Cada novo campo opcional tem uma degradação harmoniosa quando uma plataforma não consegue respeitá-lo; consulte Considerações sobre plataformas para ver a matriz de suporte de cada recurso.
Uso básico
Criação do serviço
Primeiro, inicialize o serviço de notificações:
import "github.com/wailsapp/wails/v3/pkg/application"
import "github.com/wailsapp/wails/v3/pkg/services/notifications"
// Create a new notification service
notifier := notifications.New()
//Register the service with the application
app := application.New(application.Options{
Services: []application.Service{
application.NewService(notifier),
},
})Autorização de notificações
As notificações no macOS exigem autorização do usuário. Solicite e verifique a autorização:
authorized, err := notifier.CheckNotificationAuthorization()
if err != nil {
// Handle authorization error
}
if authorized {
// Send notifications
} else {
// Request authorization
authorized, err = notifier.RequestNotificationAuthorization()
}No Windows e no Linux, isso sempre retorna true.
Tipos de notificação
Notificações básicas
Envie aos usuários uma notificação básica com ID exclusivo, título, subtítulo opcional (macOS e Linux) e texto no corpo:
notifier.SendNotification(notifications.NotificationOptions{
ID: "unique-id",
Title: "New Calendar Invite",
Subtitle: "From: Jane Doe", // Optional
Body: "Tap to view the event",
})
Notificações interativas
Envie uma notificação com botões de ação e campos de entrada de texto. Essas notificações exigem que uma categoria de notificação seja registrada primeiro:
// Define a unique category id
categoryID := "unique-category-id"
// Define a category with actions
category := notifications.NotificationCategory{
ID: categoryID,
Actions: []notifications.NotificationAction{
{
ID: "OPEN",
Title: "Open",
},
{
ID: "ARCHIVE",
Title: "Archive",
Destructive: true, /* macOS-specific */
},
},
HasReplyField: true,
ReplyPlaceholder: "message...",
ReplyButtonTitle: "Reply",
}
// Register the category
notifier.RegisterNotificationCategory(category)
// Send an interactive notification with the actions registered in the provided category
notifier.SendNotificationWithActions(notifications.NotificationOptions{
ID: "unique-id",
Title: "New Message",
Subtitle: "From: Jane Doe",
Body: "Are you able to make it?",
CategoryID: categoryID,
})Respostas às notificações
Processe as interações dos usuários com as notificações:
notifier.OnNotificationResponse(func(result notifications.NotificationResult) {
response := result.Response
fmt.Printf("Notification %s was actioned with: %s\n", response.ID, response.ActionIdentifier)
if response.ActionIdentifier == "TEXT_REPLY" {
fmt.Printf("User replied: %s\n", response.UserText)
}
if data, ok := response.UserInfo["sender"].(string); ok {
fmt.Printf("Original sender: %s\n", data)
}
// Emit an event to the frontend
app.Event.Emit("notification", result.Response)
})Personalização de notificações
Metadados personalizados
Notificações básicas e interativas podem incluir dados personalizados:
notifier.SendNotification(notifications.NotificationOptions{
ID: "unique-id",
Title: "New Calendar Invite",
Subtitle: "From: Jane Doe", // Optional
Body: "Tap to view the event",
Data: map[string]interface{}{
"sender": "jane.doe@example.com",
"timestamp": "2025-03-10T15:30:00Z",
}
})Som personalizado
Use Sound para controlar o áudio reproduzido quando uma notificação é entregue. Deixá-lo como nil reproduz o som padrão da plataforma; defina Silent: true para suprimir o som; defina Name para reproduzir um som nomeado ou incluído no pacote.
// Silent
notifier.SendNotification(notifications.NotificationOptions{
ID: "silent-id",
Title: "Background sync complete",
Sound: ¬ifications.NotificationSound{Silent: true},
})
// Named sound
notifier.SendNotification(notifications.NotificationOptions{
ID: "named-id",
Title: "New message",
Body: "Tap to read",
Sound: ¬ifications.NotificationSound{Name: "Ping"},
})Como Name é resolvido em cada plataforma:
- macOS —
Nameé passado para[UNNotificationSound soundNamed:]; o arquivo de áudio deve estar no diretórioLibrary/Soundsdo pacote da aplicação. - Windows — se
Namejá começar comms-winsoundevent:oums-appx:, será usado como está; caso contrário, será encapsulado emms-winsoundevent:para uso como nome de evento de notificação toast integrado (consulte a documentação da Microsoft sobre o esquema de<audio>das notificações toast). - Linux — encaminhado como a dica
sound-namedo freedesktop; a reprodução depende do daemon de notificações e do tema de sons ativos.
Anexos
Attachments adiciona arquivos de mídia a uma notificação. O macOS aceita vários anexos de qualquer tipo de mídia; o Windows e o Linux usam o primeiro anexo do tipo imagem.
notifier.SendNotification(notifications.NotificationOptions{
ID: "image-id",
Title: "Photo uploaded",
Body: "Tap to view",
Attachments: []notifications.NotificationAttachment{
{
ID: "preview",
Path: "/absolute/path/to/image.png",
// Type hint:
// macOS: UTI like "public.png" / "public.audio" (often inferred)
// Windows: "hero" | "appLogoOverride" | "inline" (default "inline")
// Linux: ignored
Type: "inline",
},
},
})Path deve ser um caminho absoluto do sistema de arquivos. O macOS também aceita URLs file://.
Como anexar um arquivo distribuído com a aplicação
O sistema operacional lê o anexo do disco quando a notificação é entregue, portanto Path precisa corresponder a um arquivo real na máquina do usuário final. Para um recurso incluído no pacote da aplicação (um ícone ou uma imagem incorporado com go:embed), não há um caminho absoluto fixo que possa ser definido diretamente no código, pois o arquivo fica dentro do binário, e não em um local conhecido no disco. Grave-o uma vez em um diretório gravável durante a inicialização e passe esse caminho:
import (
_ "embed"
"os"
"path/filepath"
)
//go:embed assets/preview.png
var previewPNG []byte
// Materialise the embedded asset to a stable path the OS can read.
previewPath := filepath.Join(os.TempDir(), "myapp-preview.png")
if err := os.WriteFile(previewPath, previewPNG, 0o644); err != nil {
// handle error
}
notifier.SendNotification(notifications.NotificationOptions{
ID: "image-id",
Title: "Photo uploaded",
Body: "Tap to view",
Attachments: []notifications.NotificationAttachment{
{ID: "preview", Path: previewPath, Type: "inline"},
},
})Um arquivo fornecido pelo usuário ou baixado já possui um caminho real no disco; portanto, você pode passá-lo diretamente para Path sem essa etapa. O suporte para passar os bytes do anexo na memória poderá ser adicionado em uma versão futura.
Encadeamento e agrupamento
ThreadID agrupa notificações relacionadas para que o sistema operacional possa recolhê-las na Central de Notificações/Central de Ações.
notifier.SendNotification(notifications.NotificationOptions{
ID: "msg-42",
Title: "Jane Doe",
Body: "Are you free for lunch?",
ThreadID: "chat:jane.doe",
})Nível de interrupção
InterruptionLevel controla a prioridade das notificações. Use uma das constantes exportadas:
notifier.SendNotification(notifications.NotificationOptions{
ID: "alert-id",
Title: "Server down",
Body: "Investigate immediately",
InterruptionLevel: notifications.InterruptionLevelTimeSensitive,
})| Constante | Valor | Significado |
|---|---|---|
InterruptionLevelPassive |
"passive" |
Entrega silenciosa; não acende a tela nem reproduz o som padrão |
InterruptionLevelActive |
"active" |
Nível padrão |
InterruptionLevelTimeSensitive |
"timeSensitive" |
Ignora o Foco/Não Perturbe quando permitido |
InterruptionLevelCritical |
"critical" |
Ignora o Foco e o modo silencioso; o macOS exige o direito de Alerta Crítico (sem ele, ocorre uma degradação silenciosa) |
Mapeamento por plataforma:
- macOS — define
UNNotificationContent.interruptionLevel.criticalexige o macOS 12+ e o direito de Alerta Crítico. - Windows — é mapeado para o atributo
<toast scenario="...">da notificação toast. - Linux — é mapeado para a dica
urgencydo freedesktop.
Entrega agendada
Schedule adia a entrega. Defina exatamente um entre DelaySeconds (segundos a partir de agora) e At (segundos Unix, UTC).
// Deliver in 60 seconds
notifier.SendNotification(notifications.NotificationOptions{
ID: "reminder-id",
Title: "Stand up and stretch",
Schedule: ¬ifications.NotificationSchedule{DelaySeconds: 60},
})
// Deliver at an absolute time
notifier.SendNotification(notifications.NotificationOptions{
ID: "alarm-id",
Title: "Meeting in 5 minutes",
Schedule: ¬ifications.NotificationSchedule{At: time.Now().Add(time.Hour).Unix()},
})Atualização de notificações
UpdateNotification substitui uma notificação em andamento que tenha o mesmo ID:
notifier.UpdateNotification(notifications.NotificationOptions{
ID: "download-id",
Title: "Download complete",
Body: "report.pdf is ready",
})Comportamento por plataforma:
- macOS —
UNUserNotificationCenterelimina duplicatas automaticamente pelo identificador, portanto a notificação existente é atualizada no próprio local. - Linux — usa o parâmetro D-Bus
replaces_idpara substituir a notificação anterior. - Windows — atualmente, entrega novamente como uma nova notificação. A substituição real no próprio local exige que
wintoastofereça suporte atag/groupupstream.
Considerações sobre as plataformas
No macOS, as notificações:
- Exigem autorização do usuário
- Exigem que o aplicativo seja empacotado e assinado (e notarizado para distribuição)
- Usam a aparência de notificação padrão do sistema
- Oferecem suporte a
Subtitle - Oferecem suporte à entrada de texto do usuário (respostas)
- Oferecem suporte à opção de ação
Destructive - Oferecem suporte a vários
Attachmentsde qualquer tipo de mídia (imagens, áudio e vídeo) - Oferecem suporte a
ThreadIDpara agrupamento na Central de Notificações - Oferecem suporte a todos os valores de
InterruptionLevel(criticalexige o direito de Alerta Crítico) - Oferecem suporte à entrega agendada nativa que persiste após a reinicialização do aplicativo
- Eliminam automaticamente as chamadas duplicadas de
UpdateNotificationcom base emID - Gerenciam automaticamente os modos escuro e claro
No Windows, as notificações:
- Usam os estilos de notificação toast do sistema Windows por meio do backend
wintoast - Adaptam-se às configurações de tema do Windows
- Oferecem suporte à entrada de texto do usuário (respostas)
- Oferecem suporte a telas com alta densidade de pixels (DPI)
- Não oferecem suporte a
Subtitle - Oferecem suporte a um único
Attachmentde imagem com a dica de posicionamentohero,appLogoOverrideouinline(o padrão éinline) - Oferecem suporte a
ThreadIDpara agrupamento na Central de Ações - Oferecem suporte a
InterruptionLevelpor meio do atributoscenarioda notificação toast - Oferecem suporte à entrega agendada por meio de um temporizador no processo — as notificações agendadas são perdidas se o aplicativo for encerrado antes da entrega
UpdateNotificationatualmente entrega novamente como uma nova notificação (a substituição real no próprio local aguarda o suporte upstream dewintoastatag/group)
No Linux, as notificações usam a interface D-Bus org.freedesktop.Notifications. Um daemon de notificações compatível deve estar em execução para que as notificações funcionem.
No Linux, as notificações:
- Seguem o tema do ambiente de desktop
- São posicionadas de acordo com as regras do ambiente de desktop
- Oferecem suporte a
Subtitle(concatenado ao corpo para daemons que não o renderizam separadamente) - Não oferecem suporte à entrada de texto do usuário (não faz parte da especificação freedesktop)
- Oferecem suporte a um único
Attachmentde imagem por meio da dicaimage-path - Compatível com
ThreadID(tratado pelo daemon quando houver suporte) Sound.Nameé encaminhado como a dicasound-name; a reprodução depende do daemon ativo e do tema de sons- Mapeiam
InterruptionLevelpara a dicaurgencydo freedesktop - Compatível com entrega agendada por meio de um temporizador no processo — as notificações agendadas serão perdidas se o aplicativo for encerrado antes da entrega
UpdateNotificationusa o parâmetroreplaces_iddo D-Bus para substituir a notificação anterior no mesmo lugar
Práticas recomendadas
- Verifique e solicite autorização:
- O macOS exige autorização do usuário
- Forneça notificações claras e concisas:
- Use títulos, subtítulos, textos e títulos de ações descritivos
- Trate adequadamente as respostas às notificações:
- Verifique se há erros nas respostas às notificações
- Forneça feedback para as ações do usuário
- Considere as convenções da plataforma:
- Siga os padrões de notificação específicos da plataforma
- Respeite as configurações do sistema
- No Linux, trate a dependência do daemon:
- Verifique o erro retornado por
SendNotification— a ausência de um daemon produz um erro do D-Bus - A documentação do pacote ou o README do aplicativo deve informar que é necessário um daemon de notificações compatível com freedesktop
Exemplos
Explore este exemplo:
Referência da API
Gerenciamento do serviço
| Método | Descrição |
|---|---|
New() |
Cria um novo serviço de notificações |
Autorização de notificações
| Método | Descrição |
|---|---|
RequestNotificationAuthorization() |
Solicita permissão para exibir notificações (macOS) |
CheckNotificationAuthorization() |
Verifica o status atual da autorização de notificações (macOS) |
Envio de notificações
| Método | Descrição |
|---|---|
SendNotification(options NotificationOptions) |
Envia uma notificação básica |
SendNotificationWithActions(options NotificationOptions) |
Envia uma notificação interativa com ações |
UpdateNotification(options NotificationOptions) |
Atualiza uma notificação em andamento por ID (consulte Atualização de notificações) |
Categorias de notificação
| Método | Descrição |
|---|---|
RegisterNotificationCategory(category NotificationCategory) |
Registra uma categoria de notificação reutilizável |
RemoveNotificationCategory(categoryID string) |
Remove uma categoria registrada anteriormente |
Gerenciamento de notificações
| Método | Descrição |
|---|---|
RemoveAllPendingNotifications() |
Remove todas as notificações pendentes (somente macOS e Linux) |
RemovePendingNotification(identifier string) |
Remove uma notificação pendente específica (somente macOS e Linux) |
RemoveAllDeliveredNotifications() |
Remove todas as notificações entregues (somente macOS e Linux) |
RemoveDeliveredNotification(identifier string) |
Remove uma notificação entregue específica (somente macOS e Linux) |
RemoveNotification(identifier string) |
Remove uma notificação (específico do Linux) |
Tratamento de eventos
| Método | Descrição |
|---|---|
OnNotificationResponse(callback func(result NotificationResult)) |
Registra uma função de callback para respostas às notificações |
Structs e tipos
NotificationOptions
type NotificationOptions struct {
ID string // Unique identifier for the notification (required)
Title string // Main notification title (required)
Subtitle string // Subtitle text (macOS and Linux only)
Body string // Main notification content
CategoryID string // Category identifier for interactive notifications
Data map[string]interface{} // Custom data to associate with the notification
// Sound controls the sound played on delivery. nil = platform default.
Sound *NotificationSound
// Attachments are media files shown alongside the notification.
// macOS supports multiple attachments of any media type;
// Windows and Linux honour the first image-typed attachment.
Attachments []NotificationAttachment
// ThreadID groups related notifications together in
// Notification Center / Action Center / the Linux notification daemon.
ThreadID string
// InterruptionLevel controls priority. One of "passive",
// "active" (default), "timeSensitive", "critical".
InterruptionLevel string
// Schedule defers delivery. macOS uses a native trigger that survives
// restarts; Windows and Linux use an in-process timer that does NOT.
Schedule *NotificationSchedule
}NotificationSound
type NotificationSound struct {
Silent bool // If true, no sound is played
Name string // Named/bundled sound (see "Custom Sound" above)
}NotificationAttachment
type NotificationAttachment struct {
ID string // Optional identifier
Path string // Absolute filesystem path (macOS also accepts file:// URLs)
// Type is an optional placement/UTI hint:
// macOS: UTI like "public.png" / "public.audio" (often inferred)
// Windows: "hero" | "appLogoOverride" | "inline" (default "inline")
// Linux: ignored (always image-path hint)
Type string
}NotificationSchedule
// Exactly one of DelaySeconds or At must be set. At is Unix seconds (UTC).
type NotificationSchedule struct {
DelaySeconds int // Seconds from now until delivery
At int64 // Absolute Unix timestamp (seconds, UTC)
}Constantes de InterruptionLevel
const (
InterruptionLevelPassive = "passive"
InterruptionLevelActive = "active" // default
InterruptionLevelTimeSensitive = "timeSensitive"
InterruptionLevelCritical = "critical"
)NotificationCategory
type NotificationCategory struct {
ID string // Unique identifier for the category
Actions []NotificationAction // Button actions for the notification
HasReplyField bool // Whether to include a text input field
ReplyPlaceholder string // Placeholder text for the input field
ReplyButtonTitle string // Text for the reply button
}NotificationAction
type NotificationAction struct {
ID string // Unique identifier for the action
Title string // Button text
Destructive bool // Whether the action is destructive (macOS-specific)
}NotificationResponse
type NotificationResponse struct {
ID string // Notification identifier
ActionIdentifier string // Action that was triggered
CategoryID string // Category of the notification
Title string // Title of the notification
Subtitle string // Subtitle of the notification
Body string // Body text of the notification
UserText string // Text entered by the user
UserInfo map[string]interface{} // Custom data from the notification
}NotificationResult
type NotificationResult struct {
Response NotificationResponse // Response data
Error error // Any error that occurred
}