Udostępnij za pośrednictwem


Szybki start: powiadomienia aplikacji w zestawie SDK aplikacji systemu Windows

Przechwytywanie ekranu z powiadomieniem aplikacji powyżej paska zadań. Powiadomienie jest przypomnieniem o zdarzeniu. Wyświetlana jest nazwa aplikacji, nazwa zdarzenia, czas zdarzenia i lokalizacja zdarzenia. Dane wejściowe wyboru wyświetla aktualnie wybraną wartość

W tym przewodniku Szybki start utworzysz aplikację klasyczną systemu Windows, która wysyła i odbiera powiadomienia o aplikacji lokalnej, znaną również jako wyskakujące powiadomienia przy użyciu zestawu SDK aplikacji systemu Windows .

Ważny

Powiadomienia dotyczące aplikacji z podwyższonym poziomem uprawnień (administratora) nie są obecnie obsługiwane.

Warunki wstępne

Przykładowa aplikacja

Szybki start obejmuje kod z przykładowych aplikacji powiadomień dostępnych na GitHub.

Dokumentacja interfejsu API

Aby uzyskać dokumentację referencyjną interfejsu API dla powiadomień aplikacji, zobacz Microsoft.Windows.AppNotifications Namespace.

Krok 1. Dodawanie deklaracji przestrzeni nazw

Dodaj przestrzeń nazw dla powiadomień aplikacji Windows App SDK Microsoft.Windows.AppNotifications.

using Microsoft.Windows.AppNotifications;

Krok 2. Aktualizowanie manifestu aplikacji

Jeśli aplikacja jest rozpakowana (oznacza to, że brakuje tożsamości pakietu w czasie uruchamiania), przejdź do Krok 3: Zarejestruj się, aby obsługiwać powiadomienie aplikacji.

Jeśli aplikacja jest spakowana (w tym spakowana z lokalizacją zewnętrzną):

  1. Otwórz Package.appxmanifest.
  2. Dodaj przestrzenie nazw xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" i xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" do <Package>
  3. Dodaj <desktop:Extension> dla windows.toastNotificationActivation, aby zadeklarować aktywator COM CLSID. Identyfikator CLSID można uzyskać, przechodząc do Utwórz GUID w menu Narzędzia w programie Visual Studio.
  4. Dodaj <com:Extension> dla aktywatora COM przy użyciu tego samego identyfikatora CLSID.
    1. Określ plik .exe w atrybucie Executable. Plik .exe musi być tym samym procesem wywołującym Register() podczas rejestrowania aplikacji w celu otrzymywania powiadomień, co zostało bliżej opisane w kroku 3. W poniższym przykładzie użyjemy Executable="SampleApp\SampleApp.exe".
    2. Określ Arguments="----AppNotificationActivated:", aby upewnić się, że Windows App SDK może przetworzyć treść powiadomienia jako typu AppNotification.
    3. Określ DisplayName.

Ważny

Ostrzeżenie: Jeśli zdefiniujesz typ rozszerzalności aplikacji Windows.Protocol w manifeście appx za pomocą <uap:Protocol>, kliknięcie powiadomień spowoduje uruchomienie nowych procesów tej samej aplikacji, nawet jeśli aplikacja jest już uruchomiona.

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

Krok 3. Rejestrowanie w celu obsługi powiadomienia aplikacji

Zarejestruj aplikację w celu obsługi powiadomień, a następnie wyrejestruj się po zakończeniu działania aplikacji.

W pliku App.xaml zarejestruj się dla AppNotificationManager::Default().NotificationInvoked, a następnie wywołaj AppNotificationManager::Default().Register. Kolejność tych połączeń ma znaczenie.

Ważny

Należy wywołać AppNotificationManager::Default().Register przed wywołaniem AppInstance.GetCurrent.GetActivatedEventArgs.

Po zakończeniu działania aplikacji wywołaj metodę AppNotificationManager::Default().Wyrejestruj(), aby zwolnić serwer COM i zezwolić na kolejne wywołania w celu uruchomienia nowego procesu.

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

    }
}       

Krok 4. Wyświetlanie powiadomienia aplikacji

Powiadomienie aplikacji z przyciskiem

Przed kontynuowaniem musisz ukończyć Krok 3: Zarejestruj się, aby obsłużyć powiadomienie aplikacji.

Teraz zostanie wyświetlone proste powiadomienie aplikacji z obrazem appLogoOverride i przyciskiem.

Skonstruuj powiadomienie aplikacji przy użyciu klasy AppNotificationBuilder, a następnie wywołaj Show. Aby uzyskać więcej informacji na temat tworzenia powiadomień aplikacji przy użyciu kodu XML, zapoznaj się z przykładami w temacie Zawartość powiadomień typu toast oraz w schemacie XML powiadomień .

Notatka

Jeśli aplikacja jest spakowana (w tym spakowana z lokalizacją zewnętrzną), ikona aplikacji w lewym górnym rogu powiadomienia jest pozyskiwana z package.manifest. Jeśli aplikacja jest rozpakowana, ikona jest źródłowa, najpierw przeglądając skrót, a następnie przeglądając plik zasobu w procesie aplikacji. Jeśli wszystkie próby nie powiedzą się, zostanie użyta domyślna ikona aplikacji systemu Windows. Obsługiwane typy plików ikon to .jpg, .png, .bmpi .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. 

Krok 5: Przetwarzanie wybrania powiadomienia przez użytkownika

Użytkownicy mogą wybrać treść lub przycisk powiadomienia. Aplikacja musi przetworzyć wywołanie w odpowiedzi na interakcję użytkownika z powiadomieniem.

Istnieją 2 typowe sposoby przetwarzania tego:

  1. Chcesz uruchomić aplikację w określonym kontekście interfejsu użytkownika LUB
  2. Chcesz, aby aplikacja oceniała zachowanie specyficzne dla akcji (na przykład naciśnięcie przycisku w treści powiadomienia) bez renderowania żadnego interfejsu użytkownika. Znana również jako akcja w tle.

Poniższy przykład kodu, który nie pochodzi z przykładowej aplikacji, ilustruje oba sposoby przetwarzania akcji wygenerowanej przez użytkownika. Dodaj wartość launch (odpowiada użytkownikowi klikając treść powiadomienia), element input (pole tekstowe szybkiej odpowiedzi) i przycisk z wartością arguments (odpowiada użytkownikowi klikając przycisk) do ładunku XML powiadomienia. W ProcessLaunchActivationArgsrozpatruj każdy argument osobno.

Ważny

Ustawienie activationType="background" w elemencie XML powiadomienia jest ignorowane dla aplikacji klasycznych. Zamiast tego należy przetworzyć argumenty aktywacji i zdecydować, czy wyświetlić okno, zgodnie z opisem w tym kroku.

powiadomienie aplikacji z odpowiedzią

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

Postępuj zgodnie z poniższymi wytycznymi:

  1. Jeśli użytkownik wybierze powiadomienie i aplikacja nie jest uruchomiona, oczekuje się, że aplikacja zostanie uruchomiona, a użytkownik będzie mógł zobaczyć okno pierwszego planu w kontekście powiadomienia.
  2. Jeśli użytkownik wybierze powiadomienie i aplikacja zostanie zminimalizowana, oczekuje się, że aplikacja zostanie przeniesiona na pierwszy plan, a nowe okno zostanie renderowane w kontekście powiadomienia.
  3. Jeśli akcja w tle powiadomienia jest wywoływana przez użytkownika (np. użytkownik odpowiada na powiadomienie, wpisując w polu tekstowym powiadomienia i uderzając w odpowiedź), aplikacja przetwarza ładunek bez renderowania okna pierwszego planu.

Aby uzyskać bardziej szczegółowy przykład, zobacz przykładowy kod aplikacji znaleziony w witrynie GitHub.

Krok 6. Usuwanie powiadomień

Usuń powiadomienia, gdy nie są już istotne dla użytkownika.

W tym przykładzie użytkownik zobaczył wszystkie wiadomości z czatu grupowego w Twojej aplikacji, więc wyczyść wszystkie powiadomienia z czatu grupowego. Następnie użytkownik wycisza znajomego, co powoduje usunięcie wszystkich powiadomień od tego znajomego. Najpierw dodano właściwości Group i Tag do powiadomień, zanim je wyświetlono, aby teraz móc je zidentyfikować.


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

Dodatkowe funkcje

Wysyłanie powiadomienia aplikacji opartej na chmurze

Aby wysłać powiadomienie aplikacji z chmury, wykonaj Wysyłanie powiadomienia aplikacji opartego na chmurze na stronie Szybki start: powiadomienia wypychane w zestawie SDK aplikacji systemu Windows.

Ustawianie czasu wygaśnięcia

Ustaw czas wygaśnięcia powiadomienia aplikacji przy użyciu właściwości Expiration, jeśli komunikat w powiadomieniu ma zastosowanie tylko przez określony okres czasu. Jeśli na przykład wyślesz przypomnienie o zdarzeniu kalendarza, ustaw czas wygaśnięcia na koniec wydarzenia kalendarza.

Notatka

Domyślny i maksymalny czas wygaśnięcia to 3 dni.

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

Upewnij się, że powiadomienia wygasają po ponownym uruchomieniu

Ustaw właściwość ExpiresOnReboot na wartość True, jeśli chcesz, aby powiadomienia zostały usunięte po ponownym uruchomieniu.

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

Wysyłanie i aktualizowanie powiadomienia paska postępu

Aktualizacje powiązane z paskiem postępu można wyświetlić w powiadomieniu:

Powiadomienie z paskiem postępu

Użyj konstrukcji AppNotificationProgressData, aby zaktualizować powiadomienie paska postępu.

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

Zasoby