Início rápido: notificações de aplicativo no SDK do Aplicativo 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,

Neste início rápido, você criará um aplicativo da área de trabalho do Windows que envia e recebe notificações de aplicativo local, também conhecidas como notificações do sistema, usando o SDK do Aplicativo Windows.

Importante

No momento, não há suporte para notificações para um aplicativo com privilégios elevados (administrador).

Pré-requisitos

Aplicativo de exemplo

Este início rápido aborda o código dos aplicativos de exemplo de notificações encontrados no GitHub.

Referência da API

Para obter a documentação de referência da API para notificações de aplicativo, confira o Namespace Microsoft.Windows.AppNotifications.

Etapa 1: adicionar declarações de namespace

Adicione o namespace para notificações de aplicativo do SDK do Aplicativo Windows Microsoft.Windows.AppNotifications.

using Microsoft.Windows.AppNotifications;

Etapa 2: atualizar o manifesto do aplicativo

Se o aplicativo estiver desempacotado (ou seja, ele não tem identidade de pacote no runtime), vá para a Etapa 3: Registre-se para lidar com uma notificação do aplicativo.

Se o seu aplicativo estiver empacotado (incluindo empacotado com localização externa):

  1. Abra o Package.appxmanifest.
  2. Adicionar namespaces xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" e xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" a <Package>
  3. Adicione <desktop:Extension> para windows.toastNotificationActivation para declarar o CLSID do ativador COM. Você pode obter um CLSID navegando até Criar GUID em Ferramentas no Visual Studio.
  4. Adicione <com:Extension> para o ativador COM usando o mesmo CLSID.
    1. Especifique o arquivo .exe no atributo Executable. O arquivo .exe deve ser o mesmo processo chamando Register() ao registrar seu aplicativo para notificações, o que é descrito mais na Etapa 3. No exemplo abaixo, usamos Executable="SampleApp\SampleApp.exe".
    2. Especifique Arguments="----AppNotificationActivated:" para garantir que o SDK do Aplicativo Windows possa processar o conteúdo da notificação como um tipo AppNotification.
    3. Especifique um DisplayName.

Importante

Aviso: se você definir um tipo de extensibilidade de aplicativo Windows.Protocol no manifesto appx com <uap:Protocol>, clicar em notificações iniciará novos processos do mesmo aplicativo, mesmo que o seu aplicativo já esteja em execução.

<!--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>

Etapa 3: registro para lidar com uma notificação do aplicativo

Registre seu aplicativo para lidar com notificações e cancele o registro quando seu aplicativo for encerrado.

No arquivo App.xaml, registre-se em AppNotificationManager::Default().NotificationInvoked e, em seguida, chame AppNotificationManager::Default().Register. A ordem dessas chamadas importa.

Importante

Você deve chamar AppNotificationManager::Default().Register antes de chamar AppInstance.GetCurrent.GetActivatedEventArgs.

Quando o aplicativo estiver terminando, chame AppNotificationManager::Default().Unregister() para liberar o servidor COM e permitir que as invocações subsequentes iniciem um novo processo.

// 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
        }

    }
}       

Etapa 4: exibir uma notificação do aplicativo

App notification with button

Você DEVE concluir a Etapa 3: registro para lidar com uma notificação do aplicativo antes de continuar.

Agora você exibirá uma notificação simples do aplicativo com uma imagem appLogoOverride e um botão.

Construa a notificação do aplicativo usando a classe AppNotificationBuilder e, em seguida, chame Show. Para obter mais informações sobre como construir a notificação do aplicativo usando XML, confira os exemplos de Conteúdo de notificação do sistema e o Esquema XML de notificações.

Observação

Se o aplicativo estiver empacotado (incluindo empacotado com localização externa), o ícone do aplicativo no canto superior esquerdo da notificação será originado do package.manifest. Se o aplicativo estiver desempacotado, o ícone será originado primeiro examinando o atalho e examinando o arquivo de recurso no processo do aplicativo. Se todas as tentativas falharem, o ícone do aplicativo padrão do Windows será usado. Os tipos de arquivo de ícone com suporte são .jpg, .png, .bmp e .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. 

Etapa 5: processar um usuário selecionando uma notificação

Os usuários podem selecionar o corpo ou o botão da notificação. Seu aplicativo precisa processar a invocação em resposta a um usuário interagir com sua notificação.

Há duas maneiras comuns de processar isso:

  1. Você opta por iniciar seu aplicativo em um contexto específico da interface do usuário OU
  2. Você opta por fazer com que seu aplicativo avalie um comportamento específico da ação (como pressionar um botão no corpo da notificação) sem renderizar nenhuma interface do usuário. Também conhecida como uma ação em segundo plano.

O exemplo de código abaixo, que não é do aplicativo de exemplo, ilustra as duas maneiras de processar uma ação gerada pelo usuário. Adicione um valor launch (corresponde ao usuário clicar no corpo da notificação), um elemento input (caixa de texto de resposta rápida) e um botão com um valor arguments (corresponde ao usuário clicar no botão) ao conteúdo XML da notificação. Em seu ProcessLaunchActivationArgs, ocorrência em cada argumento.

Importante

A configuração de activationType="background" no conteúdo de notificação XML é ignorada para aplicativos da área de trabalho. Em vez disso, você deve processar os argumentos de ativação e decidir se deseja exibir uma janela ou não, conforme indicado nesta etapa.

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 as diretrizes abaixo:

  1. Se uma notificação for selecionada pelo usuário e o seu aplicativo não estiver em execução, espera-se que seu aplicativo seja iniciado e o usuário possa ver a janela de primeiro plano no contexto da notificação.
  2. Se uma notificação for selecionada pelo usuário e o seu aplicativo for minimizado, espera-se que seu aplicativo seja colocado em primeiro plano e uma nova janela seja renderizada no contexto da notificação.
  3. Se uma ação em segundo plano de notificação for invocada pelo usuário (por exemplo, o usuário responde a uma notificação digitando na caixa de texto de notificação e pressionando Responder), seu aplicativo processará o conteúdo sem renderizar uma janela de primeiro plano.

Confira o código de aplicativo de exemplo encontrado no GitHub para ver um exemplo mais detalhado.

Etapa 6: remover notificações

Remova as notificações quando elas não forem mais relevantes para o usuário.

Neste exemplo, o usuário viu todas as mensagens de um chat em grupo em seu aplicativo, então você limpa todas as notificações do chat em grupo. Em seguida, o usuário ativa o mudo de um amigo, então você limpa todas as notificações do amigo. Primeiro, você adicionou as propriedades Grupo e Marca às notificações antes de exibi-las para identificá-las agora.


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);    
}

Recursos adicionais

Enviar uma notificação de aplicativo de origem na nuvem

Para enviar uma notificação de aplicativo da nuvem, siga Enviar uma notificação de aplicativo de origem na nuvem em Início rápido: notificações por push no SDK do Aplicativo Windows.

Definir um tempo de expiração

Defina um tempo de expiração na notificação do aplicativo usando a propriedade Expiration se a mensagem na notificação for relevante apenas por um determinado período de tempo. Por exemplo, se você enviar um lembrete de evento de calendário, defina o tempo de expiração para o final do evento de calendário.

Observação

O tempo de expiração padrão e máximo é de 3 dias.

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)
    }
}

Garanta que as notificações expirem na reinicialização

Defina a propriedade ExpiresOnReboot como True se você quiser que as notificações sejam excluídas na reinicialização.

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)
    }
}

Enviar e atualizar uma notificação da barra de progresso

Você pode exibir atualizações relacionadas à barra de progresso em uma notificação:

Notification with progress bar

Use o constructo AppNotificationProgressData para atualizar a notificação da barra de progresso.

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