Szybki start: powiadomienia aplikacji w zestawie SDK aplikacji systemu Windows
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
- Zaczynamy pracę z WinUI
- Utwórz nowy projekt korzystający z zestawu SDK aplikacji systemu Windows LUB Użyj zestawu SDK aplikacji systemu Windows w istniejącym projekcie
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ą):
- Otwórz Package.appxmanifest.
- Dodaj przestrzenie nazw
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
ixmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
do<Package>
- Dodaj
<desktop:Extension>
dlawindows.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. - Dodaj
<com:Extension>
dla aktywatora COM przy użyciu tego samego identyfikatora CLSID.- Określ plik .exe w atrybucie
Executable
. Plik .exe musi być tym samym procesem wywołującymRegister()
podczas rejestrowania aplikacji w celu otrzymywania powiadomień, co zostało bliżej opisane w kroku 3. W poniższym przykładzie użyjemyExecutable="SampleApp\SampleApp.exe"
. - Określ
Arguments="----AppNotificationActivated:"
, aby upewnić się, że Windows App SDK może przetworzyć treść powiadomienia jako typu AppNotification. - Określ
DisplayName
.
- Określ plik .exe w atrybucie
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
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
, .bmp
i .ico
.
- C#
- C++
// 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:
- Chcesz uruchomić aplikację w określonym kontekście interfejsu użytkownika LUB
- 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 ProcessLaunchActivationArgs
rozpatruj 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.
// 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&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&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:
- 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.
- 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.
- 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:
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
- szczegóły interfejsu API Microsoft.Windows.AppNotifications
- przykładowy kod powiadomień w witrynie GitHub
- specyfikacja powiadomień aplikacji na GitHubie
- zawartość powiadomienia toast
- XML schemat powiadomień