Freigeben über


Schnellstart: App-Benachrichtigungen im Windows App SDK

Eine Bildschirmaufnahme mit einer App-Benachrichtigung über der Taskleiste. Die Benachrichtigung ist eine Erinnerung für ein Ereignis. Der App-Name, der Ereignisname, die Ereigniszeit und der Ereignisspeicherort werden angezeigt. Eine Auswahleingabe zeigt den aktuell ausgewählten Wert

In diesem Schnellstart erstellen Sie eine Windows-Desktopanwendung, die lokale App-Benachrichtigungen sendet und empfängt, auch als Toast-Benachrichtigungen bezeichnet, mithilfe des Windows App SDK.

Important

Benachrichtigungen für eine App mit erhöhten Rechten (Administrator) werden derzeit nicht unterstützt.

Prerequisites

Sample app

In diesem Schnellstart wird Code aus den Benachrichtigungsbeispiel-Apps behandelt, die auf GitHubzu finden sind.

API reference

Api-Referenzdokumentation für App-Benachrichtigungen finden Sie unter Microsoft.Windows.AppNotifications Namespace.

Schritt 1: Hinzufügen von Namespacedeklarationen

Fügen Sie den Namespace für Windows App SDK-App-Benachrichtigungen Microsoft.Windows.AppNotificationshinzu.

using Microsoft.Windows.AppNotifications;

Schritt 2: Aktualisieren des App-Manifests

Wenn Ihre App entpackt ist (d. h., es zur Laufzeit keine Paketidentität hat), fahren Sie mit Schritt 3 fort: um sich für eine App-Benachrichtigung zu registrieren und diese zu verarbeiten.

Wenn Ihre App verpackt ist (einschließlich paketiert mit externem Speicherort):

  1. Öffnen Sie die Package.appxmanifest.
  2. Hinzufügen von xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"- und xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"-Namensräumen zu <Package>
  3. Fügen Sie <desktop:Extension> für windows.toastNotificationActivation hinzu, um Ihren COM-Aktivator CLSID-zu deklarieren. Sie können eine CLSID abrufen, indem Sie zu Erstellen von GUID- unter Tools in Visual Studio navigieren.
  4. Fügen Sie <com:Extension> für den COM-Aktivator mit demselben CLSID hinzu.
    1. Geben Sie Ihre .exe Datei im Attribut Executable an. Die EXE-Datei muss beim Registrieren Ihrer App für Benachrichtigungen derselbe Prozess Register() sein, der in Schritt 3 beschrieben wird. Im folgenden Beispiel verwenden wir Executable="SampleApp\SampleApp.exe".
    2. Geben Sie Arguments="----AppNotificationActivated:" an, um sicherzustellen, dass das Windows App SDK die Nutzlast Ihrer Benachrichtigung als AppNotification-Typ verarbeiten kann.
    3. Geben Sie eine DisplayNamean.

Important

Warnung: Wenn Sie einen Windows.Protocol- App-Erweiterbarkeitstyp in Ihrem Appx-Manifest mit <uap:Protocol>definieren, werden durch Klicken auf Benachrichtigungen neue Prozesse derselben App gestartet, auch wenn Ihre App bereits ausgeführt wird.

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

Schritt 3: Registrieren für die Behandlung einer App-Benachrichtigung

Registrieren Sie Ihre App zum Behandeln von Benachrichtigungen, und heben Sie die Registrierung auf, wenn Ihre App beendet wird.

Registrieren Sie sich in Ihrer App.xaml-Datei für AppNotificationManager::Default().NotificationInvokedund rufen Sie dann AppNotificationManager::Default().Registerauf. Die Reihenfolge dieser Aufrufe ist wichtig.

Important

Sie müssen AppNotificationManager::Default().Register aufrufen, bevor Sie AppInstance.GetCurrent.GetActivatedEventArgsaufrufen.

Rufen Sie beim Beenden Ihrer App AppNotificationManager::Default().Unregister() auf, um den COM-Server freizugeben und nachfolgende Aufrufe zum Starten eines neuen Prozesses zu ermöglichen.

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

    }
}       

Schritt 4: Anzeigen einer App-Benachrichtigung

App-Benachrichtigung mit Schaltfläche

Sie MÜSSENSchritt 3 abschließen: Registrieren, um eine App-Benachrichtigung zu behandeln, bevor Sie fortfahren.

Jetzt zeigst du eine einfache App-Benachrichtigung mit einem appLogoOverride Bild und einer Taste an.

Erstellen Sie Ihre App-Benachrichtigung mithilfe der AppNotificationBuilder- Klasse, und rufen Sie dann Showauf. Weitere Informationen zum Erstellen Ihrer App-Benachrichtigung mithilfe von XML finden Sie in den Beispielen unter Toast-Inhalt und dem Benachrichtigungs-XML-Schema.

Note

Wenn Ihre App gepackt ist (einschließlich paketiert mit externem Speicherort), wird das Symbol Ihrer App in der oberen linken Ecke der Benachrichtigung aus der package.manifeststammen. Wenn Ihre App entpackt wird, wird das Symbol zuerst durch Einen Blick auf die Verknüpfung erstellt, und dann wird die Ressourcendatei im App-Prozess betrachtet. Wenn alle Versuche fehlschlagen, wird das Windows-Standard-App-Symbol verwendet. Die unterstützten Symboldateitypen sind .jpg, .png, .bmpund .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. 

Schritt 5: Verarbeiten eines Benutzers, der eine Benachrichtigung auswählt

Benutzer können den Text oder die Schaltfläche Ihrer Benachrichtigung auswählen. Ihre App muss den Aufruf als Reaktion auf einen Benutzer verarbeiten, der mit Ihrer Benachrichtigung interagiert.

Es gibt zwei gängige Möglichkeiten, dies zu verarbeiten:

  1. Sie entscheiden, dass Ihre App in einem bestimmten UI-Kontext gestartet werden soll ODER
  2. Sie entscheiden, dass Ihre App ein aktionsspezifisches Verhalten auswertet (z. B. ein Schaltflächendruck im Benachrichtigungstext), ohne eine Benutzeroberfläche zu rendern. Bekannt auch als Hintergrundaktion.

Im folgenden Codebeispiel, das nicht aus der Beispiel-App stammt, werden beide Arten der Verarbeitung einer vom Benutzer generierten Aktion veranschaulicht. Fügen Sie einen launch Wert hinzu (entspricht dem Benutzer, der auf den Benachrichtigungstext klickt), ein input Element (Textfeld für schnelle Antwort) und eine Schaltfläche mit einem arguments Wert (entspricht dem Benutzer, der auf die Schaltfläche klickt) zur XML-Nutzlast Ihrer Benachrichtigung. In Ihrem ProcessLaunchActivationArgsFall, bei jedem Argument.

Important

Das Setzen der Einstellung activationType="background" in der XML-Nutzlast der Benachrichtigung wird für Desktop-Anwendungen ignoriert. Stattdessen müssen Sie die Aktivierungsargumente verarbeiten und entscheiden, ob ein Fenster angezeigt werden soll. Dies wird in diesem Schritt erläutert.

App-Benachrichtigung mit Antwort

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

befolgen Sie die folgenden Richtlinien:

  1. Wenn eine Benachrichtigung vom Benutzer ausgewählt wird und Ihre App nicht ausgeführt wird, wird erwartet, dass Ihre App gestartet wird und der Benutzer das Vordergrundfenster im Kontext der Benachrichtigung sehen kann.
  2. Wenn eine Benachrichtigung vom Benutzer ausgewählt wird und Ihre App minimiert wird, wird erwartet, dass Ihre App in den Vordergrund verschoben wird und ein neues Fenster im Kontext der Benachrichtigung gerendert wird.
  3. Wenn der Benutzer eine Hintergrundaktion für Benachrichtigungen aktiviert (z. B. indem er in das Benachrichtigungstextfeld tippt und auf Antworten drückt), verarbeitet Ihre App die Nutzlast, ohne ein Vordergrundfenster darzustellen.

Ein ausführlicheres Beispiel finden Sie im Code der Beispiel-App auf GitHub.

Schritt 6: Entfernen von Benachrichtigungen

Entfernen Sie Benachrichtigungen, wenn sie für den Benutzer nicht mehr relevant sind.

In diesem Beispiel hat der Benutzer alle Nachrichten aus einem Gruppenchat in Ihrer App gesehen, sodass Sie alle Benachrichtigungen aus dem Gruppenchat löschen. Anschließend schaltet der Benutzer einen Freund stumm, sodass Sie alle Benachrichtigungen des Freundes löschen. Sie haben zuerst die eigenschaften Group und Tag den Benachrichtigungen hinzugefügt, bevor sie angezeigt werden, um sie jetzt zu identifizieren.


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

Senden einer cloudbasierten App-Benachrichtigung

Um eine App-Benachrichtigung aus der Cloud zu senden, folgen Sie der Anleitung Senden einer Cloud-basierten App-Benachrichtigung unter Schnellstart: Push-Benachrichtigungen im Windows App SDK.

Festlegen einer Ablaufzeit

Legen Sie eine Ablaufzeit für Ihre App-Benachrichtigung mithilfe der eigenschaft Expiration fest, wenn die Nachricht in Ihrer Benachrichtigung nur für einen bestimmten Zeitraum relevant ist. Wenn Sie beispielsweise eine Kalenderereigniserinnerung senden, legen Sie die Ablaufzeit auf das Ende des Kalenderereignisses fest.

Note

Die Standard- und maximale Ablaufzeit beträgt 3 Tage.

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

Sicherstellen, dass Benachrichtigungen beim Neustart ablaufen

Legen Sie die eigenschaft ExpiresOnReboot auf True fest, wenn Beim Neustart Benachrichtigungen gelöscht werden sollen.

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

Senden und Aktualisieren einer Statusleistenbenachrichtigung

Sie können Aktualisierungen im Zusammenhang mit dem Fortschrittsbalken in einer Benachrichtigung anzeigen.

Benachrichtigung mit Fortschrittsbalken

Verwenden Sie das AppNotificationProgressData-Konstrukt, um die Statusleistenbenachrichtigung zu aktualisieren.

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