Ouvinte de notificação: acessar todas as notificaçõesNotification listener: Access all notifications

O ouvinte de notificação fornece acessar às notificações de um usuário.The notification listener provides access to a user's notifications. Os smartwatches e outros dispositivos acessórios podem usar o ouvinte de notificação para enviar as notificações do telefone ao dispositivo acessório.Smartwatches and other wearables can use the notification listener to send the phone's notifications to the wearable device. Os aplicativos de automação inicial podem usar o ouvinte de notificação para executar ações específicas quando as notificações são recebidas, como fazer com que as luzes pisquem quando você recebe uma chamada.Home automation apps can use notification listener to perform specific actions when notifications are received, such as making the lights blink when you receive a call.

Importante

Requer Atualização de Aniversário: você precisa usar o SDK 14393 e estar executando o build 14393 ou posterior para usar o ouvinte de notificação.Requires Anniversary Update: You must target SDK 14393 and be running build 14393 or higher to use Notification Listener.

APIs importantes: UserNotificationListener class, UserNotificationChangedTrigger classImportant APIs: UserNotificationListener class, UserNotificationChangedTrigger class

Habilitar o ouvinte adicionando a funcionalidade de notificação do usuárioEnable the listener by adding the User Notification capability

Para usar o ouvinte de notificação, você deve adicionar a funcionalidade de ouvinte de notificação ao manifesto do app.To use the notification listener, you must add the User Notification Listener capability to your app manifest.

  1. No Visual Studio, no Gerenciador de Soluções, clique duas vezes no arquivo Package.appxmanifest para abrir o designer de manifesto.In Visual Studio, in the Solution Explorer, double click your Package.appxmanifest file to open the manifest designer.
  2. Abra a guia Recursos.Open the Capabilities tab.
  3. Marque o recurso Ouvinte de Notificação de Usuário.Check the User Notification Listener capability.

Verificar se o ouvinte é compatívelCheck whether the listener is supported

Se o app oferecer suporte às versões mais antigas do Windows 10, será necessário usar a classe ApiInformation para verificar se há suporte para o listener.If your app supports older versions of Windows 10, you need to use the ApiInformation class to check whether the listener is supported. Se não houver suporte para o listener, evite a execução de chamadas às APIs do ouvinte.If the listener isn't supported, avoid executing any calls to the listener APIs.

if (ApiInformation.IsTypePresent("Windows.UI.Notifications.Management.UserNotificationListener"))
{
    // Listener supported!
}
 
else
{
    // Older version of Windows, no Listener
}

Solicitando o acesso ao ouvinteRequesting access to the listener

Assim que o ouvinte permitir o acesso às notificações do usuário, os usuários deverão dar ao app permissão para acessar suas notificações.Since the listener allows access to the user's notifications, users must give your app permission to access their notifications. Durante a experiência de primeira execução do app, você deverá solicitar acesso para usar o ouvinte de notificação.During your app's first-run experience, you should request access to use the notification listener. Se você quiser, poderá mostrar uma interface do usuário preliminar que explica por que o app precisa de acesso às notificações do usuário antes de chamar RequestAccessAsync, para que o usuário entenda por que deve permitir o acesso.If you want, you can show some preliminary UI that explains why your app needs access to the user's notifications before you call RequestAccessAsync, so that the user understands why they should allow access.

// Get the listener
UserNotificationListener listener = UserNotificationListener.Current;
 
// And request access to the user's notifications (must be called from UI thread)
UserNotificationListenerAccessStatus accessStatus = await listener.RequestAccessAsync();
 
switch (accessStatus)
{
    // This means the user has granted access.
    case UserNotificationListenerAccessStatus.Allowed:
 
        // Yay! Proceed as normal
        break;
 
    // This means the user has denied access.
    // Any further calls to RequestAccessAsync will instantly
    // return Denied. The user must go to the Windows settings
    // and manually allow access.
    case UserNotificationListenerAccessStatus.Denied:
 
        // Show UI explaining that listener features will not
        // work until user allows access.
        break;
 
    // This means the user closed the prompt without
    // selecting either allow or deny. Further calls to
    // RequestAccessAsync will show the dialog again.
    case UserNotificationListenerAccessStatus.Unspecified:
 
        // Show UI that allows the user to bring up the prompt again
        break;
}

O usuário pode revogar o acesso a qualquer momento por meio das Configurações do Windows.The user can revoke access at any time via Windows Settings. Portanto, seu aplicativo sempre deve verificar o status de acesso por meio do método GetAccessStatus antes de executar o código que usa o ouvinte de notificação.Therefore, your app should always check the access status via the GetAccessStatus method before executing code that uses the notification listener. Se o usuário revogar o acesso, as APIs apresentarão uma falha silenciosa, em vez de gerar uma exceção (por exemplo, a API que retornará todas as notificações simplesmente retornará uma lista vazia).If the user revokes access, the APIs will silently fail rather than throwing an exception (for example, the API to get all notifications will simply return an empty list).

Acessar as notificações do usuárioAccess the user's notifications

Com o ouvinte de notificação, você pode obter uma lista das notificações atuais do usuário.With the notification listener, you can get a list of the user's current notifications. Basta chamar o método GetNotificationsAsync e especificar o tipo de notificação que você deseja receber (atualmente, o único tipo de notificação com suporte são as notificações do sistema).Simply call the GetNotificationsAsync method, and specify the type of notifications you want to get (currently, the only type of notifications supported are toast notifications).

// Get the toast notifications
IReadOnlyList<UserNotification> notifs = await listener.GetNotificationsAsync(NotificationKinds.Toast);

Exibindo as notificaçõesDisplaying the notifications

Cada notificação é representada como uma UserNotification, que fornece informações sobre o app que gerou a notificação, a hora em que a notificação foi criada, a ID da notificação e a notificação propriamente.Each notification is represented as a UserNotification, which provides information about the app that the notification is from, the time the notification was created, the notification's ID, and the notification itself.

public sealed class UserNotification
{
    public AppInfo AppInfo { get; }
    public DateTimeOffset CreationTime { get; }
    public uint Id { get; }
    public Notification Notification { get; }
}

A propriedade AppInfo fornece as informações necessárias para exibir a notificação.The AppInfo property provides the info you need to display the notification.

Observação

É recomendável envolver todo o código para processar uma única notificação em um try/catch, caso ocorra uma exceção inesperada quando você estiver capturando uma única notificação.We recommend surrounding all your code for processing a single notification in a try/catch, in case an unexpected exception occurs when you are capturing a single notification. Você não deve deixar de exibir outras notificações apenas devido a um problema com uma notificação.You shouldn't completely fail to display other notifications just because of an issue with one specific notification.

// Select the first notification
UserNotification notif = notifs[0];
 
// Get the app's display name
string appDisplayName = notif.AppInfo.DisplayInfo.DisplayName;
 
// Get the app's logo
BitmapImage appLogo = new BitmapImage();
RandomAccessStreamReference appLogoStream = notif.AppInfo.DisplayInfo.GetLogo(new Size(16, 16));
await appLogo.SetSourceAsync(await appLogoStream.OpenReadAsync());

O conteúdo da notificação propriamente, como o texto da notificação, está contido na propriedade Notification.The content of the notification itself, such as the notification text, is contained in the Notification property. Essa propriedade contém a parte visual da notificação.This property contains the visual portion of the notification. (Se você estiver familiarizado com o envio de notificações no Windows, observará que as propriedades Visual e Visual.Bindings no objeto Notification correspondem ao que os desenvolvedores enviam quando exibem uma notificação).(If you are familiar with sending notifications on Windows, you will notice that the Visual and Visual.Bindings properties in the Notification object correspond to what developers send when popping a notification.)

Queremos procurar a associação da notificação do sistema (para código de prova de erro, você deve verificar se a associação não é nula).We want to look for the toast binding (for error-proof code, you should check that the binding isn't null). Na associação, você pode obter os elementos de texto.From the binding, you can obtain the text elements. Você pode escolher quantos elementos de texto deseja exibir.You can choose to display as many text elements as you would like. (O ideal é exibir todos eles.) Você pode optar por tratar os elementos de texto de forma diferente; por exemplo, trate o primeiro como texto de título e os elementos subsequentes como corpo do texto.(Ideally, you should display them all.) You can choose to treat the text elements differently; for example, treat the first one as title text, and subsequent elements as body text.

// Get the toast binding, if present
NotificationBinding toastBinding = notif.Notification.Visual.GetBinding(KnownNotificationBindings.ToastGeneric);
 
if (toastBinding != null)
{
    // And then get the text elements from the toast binding
    IReadOnlyList<AdaptiveNotificationText> textElements = toastBinding.GetTextElements();
 
    // Treat the first text element as the title text
    string titleText = textElements.FirstOrDefault()?.Text;
 
    // We'll treat all subsequent text elements as body text,
    // joining them together via newlines.
    string bodyText = string.Join("\n", textElements.Skip(1).Select(t => t.Text));
}

Remover uma notificação específicaRemove a specific notification

Se o dispositivo acessório ou o serviço permitir que o usuário ignore as notificações, você poderá remover a notificação real para que o usuário não a veja mais tarde no telefone ou no computador.If your wearable or service allows the user to dismiss notifications, you can remove the actual notification so the user doesn't see it later on their phone or PC. Basta fornecer a ID (obtida no objeto UserNotification) da notificação que você deseja remover:Simply provide the notification ID (obtained from the UserNotification object) of the notification you'd like to remove:

// Remove the notification
listener.RemoveNotification(notifId);

Limpar todas as notificaçõesClear all notifications

O método UserNotificationListener.ClearNotifications limpa todas as notificações do usuário.The UserNotificationListener.ClearNotifications method clears all the user's notifications. Use esse método com cautela.Use this method with caution. Você só deve limpar todas as notificações se o dispositivo acessório ou o serviço exibir TODAS as notificações.You should only clear all notifications if your wearable or service displays ALL notifications. Se o dispositivo acessório ou o serviço só exibir determinadas notificações, quando o usuário clicar no botão "Clear notifications", o usuário esperará que somente essas notificações sejam removidas; no entanto, se o método ClearNotifications for chamado, todas as notificações serão removidas, incluindo as que o dispositivo acessório ou o serviço não estava exibindo.If your wearable or service only displays certain notifications, when the user clicks your "Clear notifications" button, the user is only expecting those specific notifications to be removed; however, calling the ClearNotifications method would actually cause all the notifications, including ones that your wearable or service wasn't displaying, to be removed.

// Clear all notifications. Use with caution.
listener.ClearNotifications();

Tarefa em segundo plano para notificação adicionada/ignoradaBackground task for notification added/dismissed

Uma maneira comum de permitir que um aplicativo detecte as notificações é configurando uma tarefa em segundo plano, para que você possa saber quando uma notificação foi adicionada ou ignorada, independentemente do app que está sendo executado.A common way to enable an app to listen to notifications is to set up a background task, so that you can know when a notification was added or dismissed regardless of whether your app is currently running.

Graças ao modelo de processo único adicionado à Atualização de Aniversário, adicionar tarefas em segundo plano é muito simples.Thanks to the single process model added in the Anniversary Update, adding background tasks is fairly simple. No código do app principal, depois que você tiver recebido o acesso do usuário ao ouvinte de notificação e acesso para executar tarefas em segundo plano, registre uma nova tarefa em segundo plano e defina o UserNotificationChangedTrigger usando o Tipo de notificação do sistema.In your main app's code, after you have obtained the user's access to Notification Listener and obtained access to run background tasks, simply register a new background task, and set the UserNotificationChangedTrigger using the Toast notification kind.

// TODO: Request/check Listener access via UserNotificationListener.Current.RequestAccessAsync
 
// TODO: Request/check background task access via BackgroundExecutionManager.RequestAccessAsync
 
// If background task isn't registered yet
if (!BackgroundTaskRegistration.AllTasks.Any(i => i.Value.Name.Equals("UserNotificationChanged")))
{
    // Specify the background task
    var builder = new BackgroundTaskBuilder()
    {
        Name = "UserNotificationChanged"
    };
 
    // Set the trigger for Listener, listening to Toast Notifications
    builder.SetTrigger(new UserNotificationChangedTrigger(NotificationKinds.Toast));
 
    // Register the task
    builder.Register();
}

Em seguida, no App.xaml.cs, substitua o método OnBackgroundActivated, caso ainda não tenha feito isso, e use uma instrução switch no nome da tarefa para determinar quais dos seus gatilhos de tarefa em segundo plano foram invocados.Then, in your App.xaml.cs, override the OnBackgroundActivated method if you haven't yet, and use a switch statement on the task name to determine which of your many background task triggers was invoked.

protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    var deferral = args.TaskInstance.GetDeferral();
 
    switch (args.TaskInstance.Task.Name)
    {
        case "UserNotificationChanged":
            // Call your own method to process the new/removed notifications
            // The next section of documentation discusses this code
            await MyWearableHelpers.SyncNotifications();
            break;
    }
 
    deferral.Complete();
}

A tarefa em segundo plano é apenas uma chamada de atenção: ele não fornece nenhuma informação sobre quais notificações foram adicionadas ou removidas.The background task is simply a "shoulder tap": it doesn't provide any information about which specific notification was added or removed. Quando sua tarefa em segundo plano for acionada, você deverá sincronizar as notificações do dispositivo acessório para que elas reflitam as notificações da plataforma.When your background task is triggered, you should sync the notifications on your wearable so that they reflect the notifications in the platform. Isso garantirá que, se a tarefa em segundo plano apresentar falha, as notificações no dispositivo acessório ainda poderão ser recuperadas na próxima vez que a tarefa em segundo plano for executada.This ensures that if your background task fails, notifications on your wearable can still be recovered the next time your background task executes.

SyncNotifications é um método que você implementa; a próxima seção mostra como.SyncNotifications is a method you implement; the next section shows how.

Determinando quais notificações foram adicionadas e removidasDetermining which notifications were added and removed

No método SyncNotifications, para determinar quais notificações foram adicionadas ou removidas (sincronizando notificações com o dispositivo acessório), você precisa calcular o delta entre sua coleção de notificações atual e as notificações da plataforma.In your SyncNotifications method, to determine which notifications have been added or removed (syncing notifications with your wearable), you have to calculate the delta between your current notification collection, and the notifications in the platform.

// Get all the current notifications from the platform
IReadOnlyList<UserNotification> userNotifications = await listener.GetNotificationsAsync(NotificationKinds.Toast);
 
// Obtain the notifications that our wearable currently has displayed
IList<uint> wearableNotificationIds = GetNotificationsOnWearable();
 
// Copy the currently displayed into a list of notification ID's to be removed
var toBeRemoved = new List<uint>(wearableNotificationIds);
 
// For each notification in the platform
foreach (UserNotification userNotification in userNotifications)
{
    // If we've already displayed this notification
    if (wearableNotificationIds.Contains(userNotification.Id))
    {
        // We want to KEEP it displayed, so take it out of the list
        // of notifications to remove.
        toBeRemoved.Remove(userNotification.Id);
    }
 
    // Otherwise it's a new notification
    else
    {
        // Display it on the Wearable
        SendNotificationToWearable(userNotification);
    }
}
 
// Now our toBeRemoved list only contains notification ID's that no longer exist in the platform.
// So we will remove all those notifications from the wearable.
foreach (uint id in toBeRemoved)
{
    RemoveNotificationFromWearable(id);
}

Evento em primeiro plano para notificação adicionada/ignoradaForeground event for notification added/dismissed

Importante

Problema conhecido: em builds antes da compilação 17763/outubro 2018 atualização/versão 1809, o evento de primeiro plano causará um loop de CPU e/ou não funcionou.Known issue: In builds before Build 17763 / October 2018 Update / Version 1809, The foreground event will cause a CPU loop and/or didn't work. Se você precisar de suporte nessas versões anteriores, use a tarefa em segundo plano.If you need support on those earlier builds, use the background task instead.

Você também pode escutar notificações de um manipulador de eventos na memória...You can also listen to notifications from an in-memory event handler...

// Subscribe to foreground event
listener.NotificationChanged += Listener_NotificationChanged;
 
private void Listener_NotificationChanged(UserNotificationListener sender, UserNotificationChangedEventArgs args)
{
    // Your code for handling the notification
}

Como corrigir atrasos na tarefa em segundo planoHow to fix delays in the background task

Ao testar seu aplicativo, você pode observar que a tarefa em segundo plano é, às vezes, atrasada e não é disparada por vários minutos.When testing your app, you might notice that the background task is sometimes delayed and doesn't trigger for several minutes. Para corrigir o atraso, solicite que o usuário acesse as configurações do sistema-> sistema-> bateria-> uso da bateria por aplicativo, localize o aplicativo na lista, selecione-o e defina-o como "sempre permitido em segundo plano".To fix the delay, prompt the user to go to the system settings -> System -> Battery -> Battery usage by app, find your app in the list, select it, and set it to be "Always allowed in background."Depois disso, a tarefa em segundo plano sempre será disparada em até, aproximadamente, um segundo após a notificação ter sido recebida. After this, the background task should always be triggered within around a second of the notification being received.