Inicio rápido: Notificaciones de aplicaciones en el SDK de Aplicaciones para Windows

A screen capture showing an app notification above the task bar. The notification is a reminder for an event. The app name, event name, event time, and event location are shown. A selection input displays the currently selected value,

En este inicio rápido creará una aplicación de Windows de escritorio que envía y recibe notificaciones de aplicaciones locales, también conocidas como notificaciones del sistema, mediante el SDK de Aplicaciones para Windows.

Importante

Actualmente no se admiten las notificaciones de una aplicación con privilegios elevados (administrador).

Requisitos previos

Aplicación de ejemplo

En este inicio rápido se trata el código de las aplicaciones de ejemplo de notificaciones que se encuentran en GitHub.

Referencia de API

Para obtener documentación de referencia de la API para las notificaciones de aplicaciones, consulte Espacio de nombres Microsoft.Windows.AppNotifications.

Paso 1: Agregar declaraciones de espacios de nombres

Agregue el espacio de nombres para las notificaciones de aplicaciones del SDK de Aplicaciones para Windows Microsoft.Windows.AppNotifications.

using Microsoft.Windows.AppNotifications;

Paso 2: Actualizar el manifiesto de la aplicación

Si la aplicación está desempaquetada (es decir, carece de identidad de paquete en tiempo de ejecución), vaya al Paso 3: Registrarse para controlar una notificación de aplicación.

Si la aplicación está empaquetada (también con una ubicación externa):

  1. Abra el archivo Package.appxmanifest.
  2. Agregue los espacios de nombres xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" y xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" a <Package>.
  3. Agregue <desktop:Extension> para que windows.toastNotificationActivation declare el activador COM CLSID. Para obtener un CLSID, vaya a Crear GUID en Herramientas en Visual Studio.
  4. Agregue <com:Extension> para el activador COM usando el mismo CLSID.
    1. Especifique el archivo .exe en el atributo Executable. El archivo .exe debe ser el mismo proceso que llamar a Register() al registrar la aplicación para recibir notificaciones, que se describe con mayor detalle en el paso 3. En el ejemplo siguiente usamos Executable="SampleApp\SampleApp.exe".
    2. Especifique Arguments="----AppNotificationActivated:" para asegurarse de que el SDK de Aplicaciones para Windows puede procesar la carga de la notificación como un tipo AppNotification.
    3. Especifique un valor de DisplayName.

Importante

Advertencia: Si define un tipo de extensibilidad de la aplicación Windows.Protocol en el manifiesto appx con <uap:Protocol>, al hacer clic en las notificaciones se iniciarán nuevos procesos de la misma aplicación, aunque esta ya se esté ejecutando.

<!--Packaged apps only-->
<!--package.appxmanifest-->

<Package
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
  ...
  <Applications>
    <Application>
      ...
      <Extensions>

        <!--Specify which CLSID to activate when notification is clicked-->   
        <desktop:Extension Category="windows.toastNotificationActivation">
          <desktop:ToastNotificationActivation ToastActivatorCLSID="replaced-with-your-guid-C173E6ADF0C3" />
        </desktop:Extension>

        <!--Register COM CLSID-->    
        <com:Extension Category="windows.comServer">
          <com:ComServer>
            <com:ExeServer Executable="SampleApp\SampleApp.exe" DisplayName="SampleApp" Arguments="----AppNotificationActivated:">
              <com:Class Id="replaced-with-your-guid-C173E6ADF0C3" />
            </com:ExeServer>
          </com:ComServer>
        </com:Extension>
    
      </Extensions>
    </Application>
  </Applications>
 </Package>

Paso 3: Registrarse para controlar una notificación de aplicación

Registre la aplicación para controlar las notificaciones y, a continuación, anule el registro cuando finalice la aplicación.

En el archivo App.xaml, regístrese en AppNotificationManager::Default().NotificationInvoked y, a continuación, llame a AppNotificationManager::Default().Register. El orden de estas llamadas es importante.

Importante

Debe llamar a AppNotificationManager::Default().Register antes de llamar a AppInstance.GetCurrent.GetActivatedEventArgs.

Cuando la aplicación termine, llame a AppNotificationManager::Default().Unregister() para liberar el servidor COM y permitir invocaciones posteriores para iniciar un nuevo proceso.

// App.xaml.cs
namespace CsUnpackagedAppNotifications
{

    public partial class App : Application
    {
        private Window mainWindow;
        private NotificationManager notificationManager;
        
        public App()
        {
            this.InitializeComponent();
            notificationManager = new NotificationManager();
            AppDomain.CurrentDomain.ProcessExit += new EventHandler(OnProcessExit);
        }

        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            mainWindow = new MainWindow();

            notificationManager.Init();
            
            // Complete in Step 5
            
            mainWindow.Activate();
        }

        void OnProcessExit(object sender, EventArgs e)
        {
            notificationManager.Unregister();
        }
    }
}


// NotificationManager.cs
namespace CsUnpackagedAppNotifications
{
    internal class NotificationManager
    {
        private bool m_isRegistered;

        private Dictionary<string, Action<AppNotificationActivatedEventArgs>> c_map;

        public NotificationManager()
        {
            m_isRegistered = false;

            // When adding new a scenario, be sure to add its notification handler here.
            c_map = new Dictionary<int, Action<AppNotificationActivatedEventArgs>>();
            c_map.Add(ToastWithAvatar.ScenarioId, ToastWithAvatar.NotificationReceived);
            c_map.Add(ToastWithTextBox.ScenarioId, ToastWithTextBox.NotificationReceived);
        }

        ~NotificationManager()
        {
            Unregister();
        }

        public void Init()
        {
            // To ensure all Notification handling happens in this process instance, register for
            // NotificationInvoked before calling Register(). Without this a new process will
            // be launched to handle the notification.
            AppNotificationManager notificationManager = AppNotificationManager.Default;

            notificationManager.NotificationInvoked += OnNotificationInvoked;

            notificationManager.Register();
            m_isRegistered = true;
        }

        public void Unregister()
        {
            if (m_isRegistered)
            {
                AppNotificationManager.Default.Unregister();
                m_isRegistered = false;
            }
        }

        public void ProcessLaunchActivationArgs(AppNotificationActivatedEventArgs notificationActivatedEventArgs)
        {
            // Complete in Step 5
        }

    }
}       

Paso 4: Mostrar una notificación de aplicación

App notification with button

DEBE completar el paso 3: Registrarse para controlar una notificación de aplicación antes de continuar.

Ahora mostrará una notificación de aplicación sencilla con una imagen appLogoOverride y un botón.

Construya la notificación de la aplicación mediante la clase AppNotificationBuilder y, a continuación, llame a Show. Para obtener más información sobre cómo construir la notificación de la aplicación mediante XML, consulte los ejemplos de Contenido de notificaciones del sistema y de Esquema XML de notificaciones.

Nota:

Si la aplicación está empaquetada (también con una ubicación externa), el icono de la aplicación situado en la esquina superior izquierda de la notificación se originará a partir de package.manifest. Si la aplicación está desempaquetada, el icono se origina buscando primero en el acceso directo y, a continuación, examinando el archivo de recursos en el proceso de la aplicación. Si se produce un error en todos los intentos, se usará el icono de la aplicación predeterminada de Windows. Los tipos de archivo de icono admitidos son .jpg, .png, .bmp y .ico.

// ToastWithAvatar.cs
class ToastWithAvatar
{
    public const int ScenarioId = 1;
    public const string ScenarioName = "Local Toast with Avatar Image";

    public static bool SendToast()
    {
        var appNotification = new AppNotificationBuilder()
            .AddArgument("action", "ToastClick")
            .AddArgument(Common.scenarioTag, ScenarioId.ToString())
            .SetAppLogoOverride(new System.Uri("file://" + App.GetFullPathToAsset("Square150x150Logo.png")), AppNotificationImageCrop.Circle)
            .AddText(ScenarioName)
            .AddText("This is an example message using XML")
            .AddButton(new AppNotificationButton("Open App")
                .AddArgument("action", "OpenApp")
                .AddArgument(Common.scenarioTag, ScenarioId.ToString()))
            .BuildNotification();

        AppNotificationManager.Default.Show(appNotification);

        return appNotification.Id != 0; // return true (indicating success) if the toast was sent (if it has an Id)
    }

    public static void NotificationReceived(AppNotificationActivatedEventArgs notificationActivatedEventArgs)
    {
        // Complete in Step 5   
    }
}

// Call SendToast() to send a notification. 

Paso 5: Procesar un usuario seleccionando una notificación

Los usuarios pueden seleccionar el cuerpo o el botón de la notificación. La aplicación debe procesar la invocación en respuesta a un usuario que interactúe con la notificación.

Hay dos formas habituales de procesarla:

  1. Eligiendo que la aplicación se inicie en un contexto de interfaz de usuario específico; O
  2. Optando por hacer que la aplicación evalúe un comportamiento específico de la acción (como presionar un botón en el cuerpo de la notificación) sin representar ninguna interfaz de usuario. También se denomina "acción en segundo plano".

En el ejemplo de código siguiente, que no procede de la aplicación de ejemplo, se muestran ambas formas de procesar una acción generada por el usuario. Agregue un valor launch (corresponde a un usuario que hace clic en el cuerpo de la notificación), un elemento input (cuadro de texto de respuesta rápida) y un botón con un valor arguments (corresponde a un usuario que hace clic en el botón) a la carga XML de la notificación. En ProcessLaunchActivationArgs, escriba mayúsculas y minúsculas en cada argumento.

Importante

La configuración activationType="background" en la carga XML de la notificación se ignora para las aplicaciones de escritorio. En su lugar, debe procesar los argumentos de activación y decidir si desea mostrar una ventana o no, como se indica en este paso.

App notification with reply

// Example of how to process a user either selecting the notification body or inputting a quick reply in the text box. 

// Notification XML payload
//<toast launch="action=openThread&amp;threadId=92187">
//  <visual>
//      <binding template="ToastGeneric">
//          <image placement="appLogoOverride" hint-crop="circle" src="C:\<fullpath>\Logo.png"/>
//          <text>Local Toast with Avatar and Text box</text>
//          <text>This is an example message using</text>
//      </binding>
//  </visual>
//  <actions>
//      <input id="replyBox" type="text" placeHolderContent="Reply" />
//      <action
//          content="Send"
//          hint-inputId="replyBox"
//          arguments="action=reply&amp;threadId=92187" />
//  </actions>
//</toast>

void ProcessLaunchActivationArgs(const winrt::AppNotificationActivatedEventArgs& notificationActivatedEventArgs)
{
    // If the user clicks on the notification body, your app needs to launch the chat thread window
    if (std::wstring(notificationActivatedEventArgs.Argument().c_str()).find(L"openThread") != std::wstring::npos)
    {
        GenerateChatThreadWindow();
    }
    else // If the user responds to a message by clicking a button in the notification, your app needs to reply back to the other user with no window launched
    if (std::wstring(notificationActivatedEventArgs.Argument().c_str()).find(L"reply") != std::wstring::npos)
    {
        auto input = notificationActivatedEventArgs.UserInput();
        auto replyBoxText = input.Lookup(L"replyBox");

        // Process the reply text
        SendReplyToUser(replyBoxText);
    }
}

Siga las instrucciones siguientes:

  1. Si el usuario selecciona una notificación y la aplicación no se está ejecutando, se prevé que se inicie la aplicación y que el usuario pueda ver la ventana en primer plano en el contexto de la notificación.
  2. Si el usuario selecciona una notificación y la aplicación se minimiza, se prevé que la aplicación se incluya en primer plano y que se represente una nueva ventana en el contexto de la notificación.
  3. Si el usuario invoca una acción en segundo plano de la notificación (por ejemplo, el usuario responde a una notificación escribiendo en el cuadro de texto de la notificación y pulsando el botón de responder), la aplicación procesará la carga sin representar ninguna ventana en primer plano.

Consulte el código de aplicación de ejemplo que se encuentra en GitHub para ver un ejemplo más detallado.

Paso 6: Quitar notificaciones

Quite las notificaciones cuando ya no sean relevantes para el usuario.

En este ejemplo, el usuario ha visto todos los mensajes de un chat de grupo en la aplicación, por lo que borra todas las notificaciones del chat. A continuación, el usuario silencia a un amigo, por lo que borra todas las notificaciones del amigo. En primer lugar, ha agregado las propiedades Group y Tag a las notificaciones antes de mostrarlas para poder identificarlas ahora.


void SendNotification(winrt::hstring const& payload, winrt::hstring const& friendId, winrt::hstring const& groupChatId)
{
    winrt::AppNotification notification(payload);

    // Setting Group Id here allows clearing notifications from a specific chat group later
    notification.Group(groupChatId);

    // Setting Tag Id here allows clearing notifications from a specific friend later
    notification.Tag(friendId);

    winrt::AppNotificationManager::Default().Show(notification);
}

winrt::Windows::Foundation::IAsyncAction RemoveAllNotificationsFromGroupChat(const std::wstring groupChatId)
{
    winrt::AppNotificationManager manager = winrt::AppNotificationManager::Default();
    co_await manager.RemoveByGroupAsync(groupChatId);    
}

winrt::Windows::Foundation::IAsyncAction RemoveAllNotificationsFromFriend(const std::wstring friendId)
{
    winrt::AppNotificationManager manager = winrt::AppNotificationManager::Default();
    co_await manager.RemoveByTagAsync(friendId);    
}

Funciones adicionales

Envío de una notificación de aplicación de origen en la nube

Para enviar una notificación de aplicación desde la nube, siga las instrucciones de Envío de una notificación de aplicación de origen en la nube descritas en Inicio rápido: Notificaciones push en el SDK de Aplicaciones para Windows.

Establecer una hora de expiración

Establezca una hora de expiración para la notificación de la aplicación mediante la propiedad Expiration si el mensaje de la notificación solo es relevante durante un período de tiempo determinado. Por ejemplo, si envía un recordatorio para un evento del calendario, establezca la hora de expiración al final del evento.

Nota:

El tiempo de expiración predeterminado y máximo es de 3 días.

class ToastWithAvatar
{
    public static bool SendToast()
    {

        var appNotification = new AppNotificationBuilder()
            .SetAppLogoOverride(new System.Uri("ms-appx:///images/logo.png"), AppNotificationImageCrop.Circle)
            .AddText("Example expiring notification")
            .AddText("This is an example message")
            .BuildNotification();


        appNotification.Expiration = DateTime.Now.AddDays(1);
        AppNotificationManager.Default.Show(appNotification);

        return appNotification.Id != 0; // return true (indicating success) if the toast was sent (if it has an Id)
    }
}

Comprobación de que las notificaciones expiran al reiniciar

Establezca la propiedad ExpiresOnReboot en True si desea que las notificaciones se eliminen al reiniciar.

class ToastWithAvatar
{
    public static bool SendToast()
    {

        var appNotification = new AppNotificationBuilder()
            .SetAppLogoOverride(new System.Uri("ms-appx:///images/logo.png"), AppNotificationImageCrop.Circle)
            .AddText("Example ExpiresOnReboot notification")
            .AddText("This is an example message")
            .BuildNotification();


            appNotification.ExpiresOnReboot = true;
            AppNotificationManager.Default.Show(appNotification);

            return appNotification.Id != 0; // return true (indicating success) if the toast was sent (if it has an Id)
    }
}

Envío y actualización de una notificación de barra de progreso

Puede mostrar las actualizaciones relacionadas con la barra de progreso en una notificación:

Notification with progress bar

Use la construcción AppNotificationProgressData para actualizar la notificación de la barra de progreso.

const winrt::hstring c_tag = L"weekly-playlist";
const winrt::hstring c_group = L"downloads";

// Send first Notification Progress Update
void SendUpdatableNotificationWithProgress()
{
    auto notification{ winrt::AppNotificationBuilder()
            .AddText(L"Downloading this week's new music...")
            .AddProgressBar(winrt::AppNotificationProgressBar()
                .BindTitle()
                .BindValue()
                .BindValueStringOverride()
                .BindStatus())
            .BuildNotification() }

    notification.Tag(c_tag);
    notification.Group(c_group);

    // Assign initial values for first notification progress UI
    winrt::AppNotificationProgressData data(1); // Sequence number
    data.Title(L"Weekly playlist"); // Binds to {progressTitle} in xml payload
    data.Value(0.6); // Binds to {progressValue} in xml payload
    data.ValueStringOverride(L"15/26 songs"); // Binds to {progressValueString} in xml payload
    data.Status(L"Downloading..."); // Binds to {progressStatus} in xml payload

    notification.Progress(data);
    winrt::AppNotificationManager::Default().Show(notification);
}

// Send subsequent progress updates
winrt::Windows::Foundation::IAsyncAction UpdateProgressAsync()
{
    // Assign new values
    winrt::AppNotificationProgressData data(2 /* Sequence number */ );
    data.Title(L"Weekly playlist"); // Binds to {progressTitle} in xml payload
    data.Value(0.7); // Binds to {progressValue} in xml payload
    data.ValueStringOverride(L"18/26 songs"); // Binds to {progressValueString} in xml payload
    data.Status(L"Downloading..."); // Binds to {progressStatus} in xml payload

    auto result = co_await winrt::AppNotificationManager::Default().UpdateAsync(data, c_tag, c_group);
    if (result == winrt::AppNotificationProgressResult::AppNotificationNotFound)
    {
        // Progress Update failed since the previous notification update was dismissed by the user! So account for this in your logic by stopping updates or starting a new Progress Update flow.
    }
}

Recursos