Agente de escucha de notificaciones: acceso a todas las notificacionesNotification listener: Access all notifications

El agente de escucha de notificaciones proporciona acceso a las notificaciones de un usuario.The notification listener provides access to a user's notifications. Smartwatches y otros ponibles pueden usar el agente de escucha de notificaciones para enviar las notificaciones del teléfono al dispositivo portátil.Smartwatches and other wearables can use the notification listener to send the phone's notifications to the wearable device. Las aplicaciones de automatización de inicio pueden usar el agente de escucha de notificaciones para realizar acciones específicas cuando se reciben notificaciones, como hacer parpadear las luces cuando se recibe una llamada.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

Requiere actualización de aniversario: debe tener como destino el SDK 14393 y ejecutar la compilación 14393 o superior para usar el agente de escucha de notificaciones.Requires Anniversary Update: You must target SDK 14393 and be running build 14393 or higher to use Notification Listener.

API importantes: clase UserNotificationListener, clase UserNotificationChangedTriggerImportant APIs: UserNotificationListener class, UserNotificationChangedTrigger class

Habilitación del agente de escucha mediante la adición de la funcionalidad de notificación de usuarioEnable the listener by adding the User Notification capability

Para usar el agente de escucha de notificaciones, debe agregar la capacidad del agente de escucha de notificaciones de usuario al manifiesto de la aplicación.To use the notification listener, you must add the User Notification Listener capability to your app manifest.

  1. En el Explorador de soluciones de Visual Studio, haga doble clic en el Package.appxmanifest archivo para abrir el diseñador de manifiestos.In Visual Studio, in the Solution Explorer, double click your Package.appxmanifest file to open the manifest designer.
  2. Abre la pestaña Capacidades.Open the Capabilities tab.
  3. Compruebe la capacidad del agente de escucha de notificaciones de usuario .Check the User Notification Listener capability.

Comprobar si se admite el agente de escuchaCheck whether the listener is supported

Si la aplicación admite versiones anteriores de Windows 10, debe usar la clase ApiInformation para comprobar si se admite el agente de escucha.If your app supports older versions of Windows 10, you need to use the ApiInformation class to check whether the listener is supported. Si no se admite el agente de escucha, evite ejecutar llamadas a las API de agente de escucha.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
}

Solicitar acceso al agente de escuchaRequesting access to the listener

Dado que el agente de escucha permite el acceso a las notificaciones del usuario, los usuarios deben conceder permiso a su aplicación para acceder a las notificaciones.Since the listener allows access to the user's notifications, users must give your app permission to access their notifications. Durante la primera ejecución de la aplicación, debe solicitar acceso para usar el agente de escucha de notificaciones.During your app's first-run experience, you should request access to use the notification listener. Si lo desea, puede mostrar una interfaz de usuario preliminar que explica por qué la aplicación necesita acceder a las notificaciones del usuario antes de llamar a RequestAccessAsync, de modo que el usuario comprenda por qué deben permitir el acceso.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;
}

El usuario puede revocar el acceso en cualquier momento a través de la configuración de Windows.The user can revoke access at any time via Windows Settings. Por lo tanto, la aplicación debe comprobar siempre el estado de acceso a través del método GetAccessStatus antes de ejecutar el código que usa el agente de escucha de notificaciones.Therefore, your app should always check the access status via the GetAccessStatus method before executing code that uses the notification listener. Si el usuario revoca el acceso, las API producirán un error de forma silenciosa en lugar de producir una excepción (por ejemplo, la API para obtener todas las notificaciones simplemente devolverá una lista vacía).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).

Acceder a las notificaciones del usuarioAccess the user's notifications

Con el agente de escucha de notificaciones, puede obtener una lista de las notificaciones actuales del usuario.With the notification listener, you can get a list of the user's current notifications. Simplemente llame al método GetNotificationsAsync y especifique el tipo de notificaciones que desea obtener (actualmente, el único tipo de notificaciones admitidas son las notificaciones del 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);

Mostrar las notificacionesDisplaying the notifications

Cada notificación se representa como una UserNotification, que proporciona información sobre la aplicación de la que procede la notificación, la hora a la que se creó la notificación, el identificador de la notificación y la propia notificación.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; }
}

La propiedad Appinfo proporciona la información que necesita para mostrar la notificación.The AppInfo property provides the info you need to display the notification.

Nota

Se recomienda rodear todo el código para procesar una única notificación en un try/catch, en caso de que se produzca una excepción inesperada al capturar una notificación única.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. No debe realizar ninguna notificación por completo para mostrar otras notificaciones solo debido a un problema con una notificación específica.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());

El contenido de la propia notificación, como el texto de notificación, se incluye en la propiedad de notificación .The content of the notification itself, such as the notification text, is contained in the Notification property. Esta propiedad contiene la parte visual de la notificación.This property contains the visual portion of the notification. (Si está familiarizado con el envío de notificaciones en Windows, observará que las propiedades Visual y visual. bindings del objeto de notificación corresponden a lo que los desarrolladores envían cuando extraen una notificación).(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 buscar el enlace del sistema (para el código de prueba de errores, debe comprobar que el enlace no sea nulo).We want to look for the toast binding (for error-proof code, you should check that the binding isn't null). En el enlace, puede obtener los elementos de texto.From the binding, you can obtain the text elements. Puede optar por mostrar tantos elementos de texto como desee.You can choose to display as many text elements as you would like. (Idealmente, debería mostrarlos todos). Puede optar por tratar los elementos de texto de forma diferente. por ejemplo, trate el primero como texto del título y los elementos subsiguientes como texto del cuerpo.(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));
}

Quitar una notificación específicaRemove a specific notification

Si su portátil o servicio permite al usuario descartar las notificaciones, puede quitar la notificación real para que el usuario no la vea más adelante en su teléfono o equipo.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. Simplemente proporcione el identificador de notificación (obtenido del objeto UserNotification ) de la notificación que desea quitar:Simply provide the notification ID (obtained from the UserNotification object) of the notification you'd like to remove:

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

Borrar todas las notificacionesClear all notifications

El método UserNotificationListener. ClearNotifications borra todas las notificaciones del usuario.The UserNotificationListener.ClearNotifications method clears all the user's notifications. Use este método con precaución.Use this method with caution. Solo debe borrar todas las notificaciones si su portátil o servicio muestra todas las notificaciones.You should only clear all notifications if your wearable or service displays ALL notifications. Si su portátil o servicio solo muestra ciertas notificaciones, cuando el usuario hace clic en el botón "borrar notificaciones", el usuario solo espera que se quiten las notificaciones específicas; sin embargo, si se llama al método ClearNotifications , realmente se eliminarían todas las notificaciones, incluidas las que el servicio o el portátil no mostraban.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();

Tarea en segundo plano para la notificación agregada o descartadaBackground task for notification added/dismissed

Una forma habitual de permitir que una aplicación escuche notificaciones es configurar una tarea en segundo plano para que pueda saber cuándo se ha agregado o descartado una notificación independientemente de si la aplicación se está ejecutando actualmente.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.

Gracias al modelo de proceso único agregado en la actualización de aniversario, agregar tareas en segundo plano es bastante sencillo.Thanks to the single process model added in the Anniversary Update, adding background tasks is fairly simple. En el código de la aplicación principal, después de obtener el acceso del usuario al agente de escucha de notificaciones y obtener acceso para ejecutar las tareas en segundo plano, simplemente registre una nueva tarea en segundo plano y establezca UserNotificationChangedTrigger con el tipo de notificación del 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();
}

Después, en el App.xaml.cs, invalide el método OnBackgroundActivated si todavía no lo ha hecho, y use una instrucción switch en el nombre de la tarea para determinar qué desencadenadores de tareas en segundo plano se invocaron.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();
}

La tarea en segundo plano es simplemente una "TAP de hombro": no proporciona ninguna información sobre la notificación específica que se ha agregado o quitado.The background task is simply a "shoulder tap": it doesn't provide any information about which specific notification was added or removed. Cuando se desencadene la tarea en segundo plano, debe sincronizar las notificaciones en el portátil para que reflejen las notificaciones en la plataforma.When your background task is triggered, you should sync the notifications on your wearable so that they reflect the notifications in the platform. Esto garantiza que, si se produce un error en la tarea en segundo plano, las notificaciones en el portátil se pueden recuperar la próxima vez que se ejecute la tarea en segundo plano.This ensures that if your background task fails, notifications on your wearable can still be recovered the next time your background task executes.

SyncNotifications es un método que se implementa; en la sección siguiente se muestra cómo.SyncNotifications is a method you implement; the next section shows how.

Determinar qué notificaciones se agregaron y quitaronDetermining which notifications were added and removed

En el SyncNotifications método, para determinar qué notificaciones se han agregado o quitado (sincronizando las notificaciones con el portátil), tiene que calcular la diferencia entre la colección de notificaciones actual y las notificaciones de la 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 de primer plano para la notificación agregada o descartadaForeground event for notification added/dismissed

Importante

Problema conocido: en las compilaciones anteriores a la compilación 17763/octubre 2018 actualización/versión 1809, el evento de primer plano producirá un bucle de CPU o no funcionó.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. Si necesita compatibilidad con esas compilaciones anteriores, utilice en su lugar la tarea en segundo plano.If you need support on those earlier builds, use the background task instead.

También puede escuchar notificaciones de un controlador de eventos en memoria...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
}

Cómo corregir retrasos en la tarea en segundo planoHow to fix delays in the background task

Al probar la aplicación, es posible que observe que la tarea en segundo plano se retrasa en ocasiones y no se desencadena durante varios minutos.When testing your app, you might notice that the background task is sometimes delayed and doesn't trigger for several minutes. Para corregir el retraso, pida al usuario que vaya a la configuración del sistema: > batería del > del sistema > uso de la batería por la aplicación, busque la aplicación en la lista, selecciónela y establézcala en "siempre permitido en 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."Después, la tarea en segundo plano debe desencadenarse siempre en torno a un segundo de la notificación recibida. After this, the background task should always be triggered within around a second of the notification being received.