Condividi tramite


Avvio rapido: Notifiche delle app nel Windows App SDK

Cattura dello schermo che mostra una notifica dell'applicazione sopra la barra delle applicazioni. La notifica è un promemoria per un evento. Vengono visualizzati il nome dell'applicazione, il nome dell'evento, l'ora dell'evento e il luogo dell'evento. Un input di selezione visualizza il valore attualmente selezionato,

In questa guida introduttiva si creerà un'applicazione desktop di Windows che invia e riceve notifiche di app locali, note anche come notifiche di tipo avviso popup, usando Windows App SDK.

Important

Le notifiche per un'app con privilegi elevati (amministratore) non sono attualmente supportate.

Prerequisites

Sample app

Questa guida introduttiva illustra il codice delle app di esempio di notifiche disponibili in GitHub.

API reference

Per la documentazione di riferimento sulle API per le notifiche delle app, vedere spazio dei nomi Microsoft.Windows.AppNotifications.

Passaggio 1: Aggiungere dichiarazioni di namespace

Aggiungere lo spazio dei nomi per le notifiche delle applicazioni del Windows App SDK Microsoft.Windows.AppNotifications.

using Microsoft.Windows.AppNotifications;

Passaggio 2: Aggiornare il manifesto dell'app

Se l'app non è impacchettata (cioè manca l'identità del pacchetto durante l'esecuzione), passa a Passaggio 3: Registrati per gestire una notifica dell'app.

Se l'app viene inserita in un pacchetto (incluso il pacchetto con la posizione esterna):

  1. Aprire il Package.appxmanifest.
  2. Aggiungere spazi dei nomi xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" e xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" a <Package>
  3. Aggiungere <desktop:Extension> per windows.toastNotificationActivation per definire il tuo attivatore COM con CLSID . È possibile ottenere un CLSID passando a Crea GUID sotto Strumenti in Visual Studio.
  4. Aggiungi <com:Extension> all'attivatore COM utilizzando lo stesso CLSID.
    1. Specificare il file .exe nell'attributo Executable. Il file .exe deve essere gestito dallo stesso processo che chiama Register() quando si registra l'app per le notifiche, come descritto in dettaglio in Passaggio 3. Nell'esempio seguente, usiamo Executable="SampleApp\SampleApp.exe".
    2. Specificare Arguments="----AppNotificationActivated:" per garantire che Windows App SDK possa elaborare il payload della notifica come una notifica di tipo AppNotification.
    3. Specificare un DisplayName.

Important

Avviso: se nel manifesto appx definisci un tipo di estendibilità dell'app Windows.Protocol con <uap:Protocol>, facendo clic sulle notifiche verranno avviati nuovi processi della stessa app, anche se è già in esecuzione.

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

Passaggio 3: Eseguire la registrazione per gestire una notifica dell'app

Registra la tua app per gestire le notifiche, quindi annulla la registrazione quando l'app termina.

Nel file App.xaml, iscriversi a AppNotificationManager::Default().NotificationInvoked, quindi chiamare AppNotificationManager::Default().Register. L'ordine di queste chiamate è importante.

Important

È necessario chiamare AppNotificationManager::D efault(). Registrare prima di chiamare AppInstance.GetCurrent.GetActivatedEventArgs.

Quando l'app termina, chiama AppNotificationManager::Default().Unregister() per liberare il server COM e consentire alle invocazioni successive di avviare un nuovo 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<int, 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
        }

    }
}       

Passaggio 4: Visualizzare una notifica dell'app

notifica dell'app con pulsante

È NECESSARIO completare Passaggio 3: Registrarsi per gestire una notifica dell'app prima di procedere.

A questo punto si visualizzerà una semplice notifica dell'app con una appLogoOverride immagine e un pulsante.

Costruisci la notifica dell'app usando la classe AppNotificationBuilder e quindi chiama Show. Per altre informazioni su come costruire la notifica dell'app tramite XML, vedere gli esempi in Contenuto dell'avviso popup e lo schema XML delle notifiche.

Note

Se l'app viene inserita in un pacchetto (incluso il pacchetto con posizione esterna), l'icona dell'app nell'angolo superiore sinistro della notifica viene originata dalla package.manifest. Se l'app è non impacchettata, l'icona viene ottenuta prima esaminando la scorciatoia e poi il file di risorse nel processo dell'applicazione. Se tutti i tentativi hanno esito negativo, viene usata l'icona dell'app predefinita di Windows. Sono supportati i tipi di file .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. 

Passaggio 5: Elaborare la selezione di una notifica da parte di un utente

Gli utenti possono selezionare il corpo o il pulsante della tua notifica. L'app deve elaborare la chiamata in risposta a un utente che interagisce con la notifica.

Esistono due modi comuni per elaborare questa procedura:

  1. Scegli di avviare l'app in un contesto dell'interfaccia specifico OPPURE
  2. Si sceglie di fare in modo che l'app valuti un comportamento specifico dell'azione (ad esempio un pulsante premuto nel corpo della notifica) senza eseguire il rendering dell'interfaccia utente. Nota anche come azione in background.

L'esempio di codice seguente, che non proviene dall'app di esempio, illustra entrambi i modi di elaborazione di un'azione generata dall'utente. Aggiungere un launch valore (corrisponde all'utente facendo clic sul corpo della notifica), un input elemento (casella di testo risposta rapida) e un pulsante con un arguments valore (corrisponde all'utente che fa clic sul pulsante) al payload XML della notifica. Nel ProcessLaunchActivationArgs, valuta ogni argomento.

Important

L'impostazione activationType="background" nel payload XML di notifica viene ignorata per le applicazioni desktop. È invece necessario elaborare gli argomenti di attivazione e decidere se visualizzare una finestra o meno, come indicato in questo passaggio.

notifica dell'app con risposta

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

Attenersi alle linee guida seguenti:

  1. Se l'utente seleziona una notifica e l'app non è in esecuzione, è previsto che l'app venga avviata e che l'utente possa visualizzare la finestra in primo piano nel contesto della notifica.
  2. Se l'utente seleziona una notifica e l'app viene ridotta a icona, è previsto che l'app venga portata in primo piano e che venga eseguito il rendering di una nuova finestra nel contesto della notifica.
  3. Se un'azione in background di notifica viene richiamata dall'utente (ad esempio, l'utente risponde a una notifica digitando nella casella di testo della notifica e selezionando la risposta), l'app elabora il payload senza eseguire il rendering di una finestra in primo piano.

Per un esempio più dettagliato, vedere il codice dell'app di esempio disponibile in GitHub .

Passaggio 6: Rimuovere le notifiche

Rimuovere le notifiche quando non sono più rilevanti per l'utente.

In questo esempio, l'utente ha visto tutti i messaggi di una chat di gruppo nell'app, in modo da cancellare tutte le notifiche dalla chat di gruppo. Quindi, l'utente disattiva un amico, in modo da cancellare tutte le notifiche dall'amico. Per identificare le notifiche, hai prima aggiunto le proprietà Group e Tag prima di visualizzarle.


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

Additional features

Invio di una notifica dell'app di origine cloud

Per inviare una notifica dell'app dal cloud, seguire Inviare una notifica di app con origine cloud all'indirizzo Avvio rapido: Notifiche push in Windows App SDK.

Impostare un'ora di scadenza

Impostare un'ora di scadenza per la notifica dell'app usando la Expiration proprietà se il messaggio nella notifica è rilevante solo per un determinato periodo di tempo. Ad esempio, se si invia un promemoria dell'evento del calendario, impostare l'ora di scadenza sulla fine dell'evento del calendario.

Note

Il tempo di scadenza predefinito e massimo è di 3 giorni.

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

Assicurarsi che le notifiche scadano al riavvio

Impostare la ExpiresOnReboot proprietà su Vero se si desidera che le notifiche vengano eliminate al riavvio.

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

Invia e aggiorna una notifica della barra di progresso

È possibile visualizzare gli aggiornamenti correlati alla barra di stato in una notifica:

Notifica con barra di avanzamento

Usare il costrutto AppNotificationProgressData per aggiornare la notifica della barra di avanzamento.

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

Resources