Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Spakowane i rozpakowane aplikacje klasyczne mogą wysyłać interaktywne app powiadomienia, podobnie jak aplikacje platformy uniwersalnej systemu Windows (UWP). Obejmuje to aplikacje opakowane (zobacz Utwórz nowy projekt dla aplikacji WinUI 3 opakowanej w pulpitapp); aplikacje opakowane z lokalizacją zewnętrzną (zobacz Nadawanie tożsamości pakietu przez opakowanie z lokalizacją zewnętrzną) i aplikacje niepakowane (zobacz Utwórz nowy projekt dla rozpakowanej aplikacji WinUI 3 na pulpitapp).
Jednak w przypadku pulpitu nieopakowanego app, istnieje kilka specjalnych kroków. Wynika to z różnych schematów aktywacji i braku tożsamości pakietu w czasie wykonywania.
Note
Termin "toast powiadomienie" jest zastępowany terminem "app powiadomienie". Te dwa terminy odnoszą się do tej samej funkcji systemu Windows, ale z czasem wycofamy korzystanie z "toast powiadomienia" w dokumentacji.
Important
Jeśli piszesz aplikację UWP app, zapoznaj się z dokumentacją UWP. W przypadku innych języków desktopowych zobacz Desktop C#.
Krok 1. Włączanie zestawu Windows SDK
Jeśli nie włączono zestawu Windows SDK dla elementu app, należy to zrobić najpierw. Istnieje kilka kluczowych kroków.
- Dodaj
runtimeobject.libjako dodatkowe zależności do . - Element docelowy zestawu Windows SDK.
Kliknij prawym przyciskiem myszy na projekt i wybierz Właściwości .
W górnym menu Konfiguracja wybierz pozycję Wszystkie konfiguracje, aby następująca zmiana była stosowana zarówno do Debug, jak i Release.
W obszarze konsolidatora —> Wejście, dodaj runtimeobject.lib do Dodatkowe Zależności.
Następnie w obszarze Ogólneupewnij się, że Windows SDK w wersji ustaw na wersję 10.0 lub nowszą.
Krok 2. Kopiowanie kodu biblioteki compat
Skopiuj plik DesktopNotificationManagerCompat.h i DesktopNotificationManagerCompat.cpp z usługi GitHub do projektu. Biblioteka compat upraszcza znaczną złożoność powiadomień na pulpicie. Poniższe instrukcje wymagają biblioteki kompatybilności.
Jeśli używasz wstępnie skompilowanych nagłówków, upewnij się, że #include "stdafx.h" znajduje się jako pierwszy wiersz w pliku DesktopNotificationManagerCompat.cpp.
Krok 3. Dołączanie plików nagłówków i przestrzeni nazw
Dołącz plik nagłówka biblioteki compat oraz pliki nagłówka i przestrzenie nazw związane z używaniem interfejsów API powiadomień systemu Windows.
#include "DesktopNotificationManagerCompat.h"
#include <NotificationActivationCallback.h>
#include <windows.ui.notifications.h>
using namespace ABI::Windows::Data::Xml::Dom;
using namespace ABI::Windows::UI::Notifications;
using namespace Microsoft::WRL;
Krok 4. Implementowanie aktywatora
Należy zaimplementować procedurę obsługi app aktywacji powiadomień, aby po kliknięciu powiadomienia przez użytkownika app mógł wykonać określone działania. Jest to wymagane, aby powiadomienie pozostawało w Centrum akcji (ponieważ powiadomienie można kliknąć kilka dni później, gdy app jest zamknięte). Tę klasę można umieścić w dowolnym miejscu w projekcie.
Zaimplementuj interfejs INotificationActivationCallback, jak pokazano poniżej, w tym identyfikator UUID. Wywołaj także CoCreatableClass, aby oznaczyć swoją klasę jako tworzoną przez COM. Dla UUID, utwórz unikatowy GUID przy użyciu jednego z wielu dostępnych generatorów online. Ten identyfikator CLSID (identyfikator klasy GUID) to sposób, w jaki Centrum akcji rozpoznaje, jaką klasę aktywować w COM.
// The UUID CLSID must be unique to your app. Create a new GUID if copying this code.
class DECLSPEC_UUID("replaced-with-your-guid-C173E6ADF0C3") NotificationActivator WrlSealed WrlFinal
: public RuntimeClass<RuntimeClassFlags<ClassicCom>, INotificationActivationCallback>
{
public:
virtual HRESULT STDMETHODCALLTYPE Activate(
_In_ LPCWSTR appUserModelId,
_In_ LPCWSTR invokedArgs,
_In_reads_(dataCount) const NOTIFICATION_USER_INPUT_DATA* data,
ULONG dataCount) override
{
// TODO: Handle activation
}
};
// Flag class as COM creatable
CoCreatableClass(NotificationActivator);
Krok 5. Rejestrowanie za pomocą platformy powiadomień
Następnie należy zarejestrować się na platformie powiadomień. Istnieją różne kroki w zależności od tego, czy app pakiet został spakowany, czy rozpakowany. Jeśli obsługujesz obie opcje, musisz wykonać oba zestawy kroków (jednak nie ma potrzeby tworzenia rozgałęzienia kodu, ponieważ nasza biblioteka zajmuje się tym za Ciebie).
Packaged
app Jeśli twój app jest opakowany (zobacz Tworzenie nowego projektu dla opakowanego pulpitu WinUI 3) lub opakowany z lokalizacją zewnętrzną (zobacz Udzielanie tożsamości pakietu przez opakowanie z lokalizacją zewnętrzną) lub jeśli obsługujesz oba te elementy, dodaj w swoim Package.appxmanifest:
- Deklaracja dla xmlns:com
- Deklaracja xmlns:desktop
- W atrybucie IgnorableNamespaces, com i desktop
-
com:Extension dla aktywatora COM, wykorzystując identyfikator GUID z kroku 4. Pamiętaj, aby uwzględnić element
Arguments="-ToastActivated", żeby wiedzieć, że uruchomienie pochodzi z powiadomienia app. - desktop:Extension for windows.toastNotificationActivation aby zadeklarować app identyfikator CLSID aktywatora powiadomień (identyfikator GUID z kroku 4).
Package.appxmanifest
<Package
...
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
IgnorableNamespaces="... com desktop">
...
<Applications>
<Application>
...
<Extensions>
<!--Register COM CLSID LocalServer32 registry key-->
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="YourProject\YourProject.exe" Arguments="-ToastActivated" DisplayName="Toast activator">
<com:Class Id="replaced-with-your-guid-C173E6ADF0C3" DisplayName="Toast activator"/>
</com:ExeServer>
</com:ComServer>
</com:Extension>
<!--Specify which CLSID to activate when toast clicked-->
<desktop:Extension Category="windows.toastNotificationActivation">
<desktop:ToastNotificationActivation ToastActivatorCLSID="replaced-with-your-guid-C173E6ADF0C3" />
</desktop:Extension>
</Extensions>
</Application>
</Applications>
</Package>
Unpackaged
Jeśli twój app jest rozpakowany (zobacz Tworzenie nowego projektu dla rozpakowanego pulpitu appWinUI 3 ), lub jeśli obsługujesz oba te elementy, musisz zadeklarować identyfikator modelu użytkownika aplikacji (AUMID) i toast identyfikator CLSID aktywatora (identyfikator GUID z kroku 4) na appskrót w menu Start.
Wybierz unikatowy identyfikator AUMID, który zidentyfikuje twój appelement. Jest to zwykle w postaci [CompanyName]. [AppName]. Ale chcesz mieć pewność, że jest ona unikatowa we wszystkich aplikacjach (więc możesz dodać kilka cyfr na końcu).
Krok 5.1. Instalator WiX
Jeśli używasz WiX dla instalatora, zmodyfikuj plik Product.wxs , aby dodać dwie właściwości skrótu do skrótu menu Start, jak pokazano poniżej. Upewnij się, że identyfikator GUID z kroku #4 znajduje się w {}, jak pokazano niżej.
Product.wxs
<Shortcut Id="ApplicationStartMenuShortcut" Name="Wix Sample" Description="Wix Sample" Target="[INSTALLFOLDER]WixSample.exe" WorkingDirectory="INSTALLFOLDER">
<!--AUMID-->
<ShortcutProperty Key="System.AppUserModel.ID" Value="YourCompany.YourApp"/>
<!--COM CLSID-->
<ShortcutProperty Key="System.AppUserModel.ToastActivatorCLSID" Value="{replaced-with-your-guid-C173E6ADF0C3}"/>
</Shortcut>
Important
Aby faktycznie używać powiadomień, musisz najpierw zainstalować swój app za pomocą instalatora przed przystąpieniem do debugowania, aby skrót Start z Twoim identyfikatorem AUMID i CLSID był obecny. Po zapoznaniu się ze skrótem Start można debugować przy użyciu F5 w programie Visual Studio.
Krok 5.2. Rejestrowanie identyfikatora AUMID i serwera COM
Następnie, niezależnie od instalatora, w kodzie uruchamiania app (przed wywołaniem dowolnych interfejsów API powiadomień) wywołaj metodę RegisterAumidAndComServer, podając klasę aktywatora powiadomień z kroku 4 i użyty powyżej identyfikator AUMID.
// Register AUMID and COM server (for a packaged app, this is a no-operation)
hr = DesktopNotificationManagerCompat::RegisterAumidAndComServer(L"YourCompany.YourApp", __uuidof(NotificationActivator));
Jeśli aplikacja app obsługuje zarówno spakowane, jak i rozpakowane wdrożenie, możesz wywołać tę metodę niezależnie od tego. Jeśli uruchamiasz pakietowaną aplikację (czyli z tożsamością pakietu w czasie wykonywania), ta metoda natychmiast zwróci wynik. Nie ma potrzeby rozwidlenia kodu.
Ta metoda umożliwia wywoływanie interfejsów API kompatybilności do wysyłania i zarządzania powiadomieniami, bez konieczności ciągłego podawania identyfikatora AUMID. Wstawia on klucz rejestru LocalServer32 dla serwera COM.
Krok 6. Rejestrowanie aktywatora COM
W przypadku aplikacji pakietowych i niepakietowych należy zarejestrować typ aktywatora powiadomień, aby móc obsługiwać toast aktywacje.
W kodzie startowym Twojego app wywołaj następującą metodę RegisterActivator. Należy to wywołać, aby otrzymać jakiekolwiek toast aktywacje.
// Register activator type
hr = DesktopNotificationManagerCompat::RegisterActivator();
Krok 7. Wysyłanie powiadomienia
Wysyłanie powiadomienia jest identyczne z aplikacjami platformy UWP, z tą różnicą, że do utworzenia elementu ToastNotifier użyjesz elementu DesktopNotificationManagerCompat. Biblioteka compat automatycznie obsługuje różnicę między spakowanymi a niespakowanymi aplikacjami, więc nie musisz rozgałęziać swojego kodu. W przypadku rozpakowanego app biblioteka compat buforuje identyfikator AUMID, który został podany przy wywołaniu RegisterAumidAndComServer, abyś nie musiał martwić się o to, kiedy podać lub nie podać identyfikatora AUMID.
Upewnij się, że używasz powiązania ToastGeneric , jak pokazano poniżej, ponieważ starsze szablony powiadomień systemu Windows 8.1 toast nie aktywują aktywatora powiadomień COM utworzonego w kroku 4.
Important
Obrazy HTTP są obsługiwane tylko w spakowanych aplikacjach, które w swoim manifeście mają uprawnienia do internetu. Aplikacje bez pakietu nie obsługują obrazów http, musisz pobrać obraz do swoich danych lokalnych app i odwoływać się do niego lokalnie.
// Construct XML
ComPtr<IXmlDocument> doc;
hr = DesktopNotificationManagerCompat::CreateXmlDocumentFromString(
L"<toast><visual><binding template='ToastGeneric'><text>Hello world</text></binding></visual></toast>",
&doc);
if (SUCCEEDED(hr))
{
// See full code sample to learn how to inject dynamic text, buttons, and more
// Create the notifier
// Desktop apps must use the compat method to create the notifier.
ComPtr<IToastNotifier> notifier;
hr = DesktopNotificationManagerCompat::CreateToastNotifier(¬ifier);
if (SUCCEEDED(hr))
{
// Create the notification itself (using helper method from compat library)
ComPtr<IToastNotification> toast;
hr = DesktopNotificationManagerCompat::CreateToastNotification(doc.Get(), &toast);
if (SUCCEEDED(hr))
{
// And show it!
hr = notifier->Show(toast.Get());
}
}
}
Important
Aplikacje klasyczne nie mogą używać starszych toast szablonów (takich jak ToastText02). Aktywacja starszych szablonów zakończy się niepowodzeniem, gdy zostanie określony identyfikator CLSID COM. Należy użyć szablonów ToastGeneric systemu Windows, jak pokazano powyżej.
Krok 8. Obsługa aktywacji
Gdy użytkownik kliknie powiadomienie app lub przyciski w powiadomieniu, zostanie wywołana metoda Activate klasy NotificationActivator .
Wewnątrz metody Activate można przeanalizować argumenty określone w powiadomieniu i uzyskać dane wejściowe, które użytkownik wpisał lub wybrał, a następnie odpowiednio aktywować app.
Note
Metoda Activate jest wywoływana w osobnym wątku od głównego wątku.
// The GUID must be unique to your app. Create a new GUID if copying this code.
class DECLSPEC_UUID("replaced-with-your-guid-C173E6ADF0C3") NotificationActivator WrlSealed WrlFinal
: public RuntimeClass<RuntimeClassFlags<ClassicCom>, INotificationActivationCallback>
{
public:
virtual HRESULT STDMETHODCALLTYPE Activate(
_In_ LPCWSTR appUserModelId,
_In_ LPCWSTR invokedArgs,
_In_reads_(dataCount) const NOTIFICATION_USER_INPUT_DATA* data,
ULONG dataCount) override
{
std::wstring arguments(invokedArgs);
HRESULT hr = S_OK;
// Background: Quick reply to the conversation
if (arguments.find(L"action=reply") == 0)
{
// Get the response user typed.
// We know this is first and only user input since our toasts only have one input
LPCWSTR response = data[0].Value;
hr = DesktopToastsApp::SendResponse(response);
}
else
{
// The remaining scenarios are foreground activations,
// so we first make sure we have a window open and in foreground
hr = DesktopToastsApp::GetInstance()->OpenWindowIfNeeded();
if (SUCCEEDED(hr))
{
// Open the image
if (arguments.find(L"action=viewImage") == 0)
{
hr = DesktopToastsApp::GetInstance()->OpenImage();
}
// Open the app itself
// User might have clicked on app title in Action Center which launches with empty args
else
{
// Nothing to do, already launched
}
}
}
if (FAILED(hr))
{
// Log failed HRESULT
}
return S_OK;
}
~NotificationActivator()
{
// If we don't have window open
if (!DesktopToastsApp::GetInstance()->HasWindow())
{
// Exit (this is for background activation scenarios)
exit(0);
}
}
};
// Flag class as COM creatable
CoCreatableClass(NotificationActivator);
Aby prawidłowo obsługiwać uruchamianie w stanie zamkniętym, w funkcji WinMain należy określić, czy uruchamiasz się z app powiadomienia, czy nie. Jeśli uruchomiono z powiadomienia, będzie argument uruchomienia "-ToastActivated". Gdy to zobaczysz, powinieneś przestać wykonywać jakikolwiek normalny kod aktywacji uruchamiania i zezwolić, aby NotificationActivator uruchamiał okna w razie potrzeby.
// Main function
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE, _In_ LPWSTR cmdLineArgs, _In_ int)
{
RoInitializeWrapper winRtInitializer(RO_INIT_MULTITHREADED);
HRESULT hr = winRtInitializer;
if (SUCCEEDED(hr))
{
// Register AUMID and COM server (for a packaged app, this is a no-operation)
hr = DesktopNotificationManagerCompat::RegisterAumidAndComServer(L"WindowsNotifications.DesktopToastsCpp", __uuidof(NotificationActivator));
if (SUCCEEDED(hr))
{
// Register activator type
hr = DesktopNotificationManagerCompat::RegisterActivator();
if (SUCCEEDED(hr))
{
DesktopToastsApp app;
app.SetHInstance(hInstance);
std::wstring cmdLineArgsStr(cmdLineArgs);
// If launched from toast
if (cmdLineArgsStr.find(TOAST_ACTIVATED_LAUNCH_ARG) != std::string::npos)
{
// Let our NotificationActivator handle activation
}
else
{
// Otherwise launch like normal
app.Initialize(hInstance);
}
app.RunMessageLoop();
}
}
}
return SUCCEEDED(hr);
}
Sekwencja aktywacji zdarzeń
Sekwencja aktywacji jest następująca...
Jeśli twój app jest już uruchomiony:
- w NotificationActivator następuje aktywowanie
Jeśli twój app nie jest uruchomiony:
- Twój app plik EXE jest uruchomiony, otrzymasz argumenty wiersza polecenia "-ToastActivated".
- w NotificationActivator następuje aktywowanie
Aktywacja na pierwszym planie a aktywacja w tle
W przypadku aplikacji komputerowych aktywacja pierwszego planu i tła jest obsługiwana identycznie — wywoływany jest aktywator COM. To kod app decyduje, czy pokazać okno, czy po prostu wykonać pewną czynność i zakończyć. W związku z tym określenie typu aktywacji jako background w app zawartości powiadomień nie zmienia zachowania.
Krok 9. Usuwanie powiadomień i zarządzanie nimi
Usuwanie powiadomień i zarządzanie nimi jest identyczne z aplikacjami platformy UWP. Zalecamy jednak użycie naszej biblioteki zgodności, aby uzyskać DesktopNotificationHistoryCompat, dzięki czemu nie trzeba się martwić o podanie AUMID dla powiadomień na pulpicie app.
std::unique_ptr<DesktopNotificationHistoryCompat> history;
auto hr = DesktopNotificationManagerCompat::get_History(&history);
if (SUCCEEDED(hr))
{
// Remove a specific toast
hr = history->Remove(L"Message2");
// Clear all toasts
hr = history->Clear();
}
Krok 10. Wdrażanie i debugowanie
Aby wdrożyć i debugować spakowany app, zobacz Uruchamianie, debugowanie i testowanie spakowanej aplikacji desktopowej app.
Aby wdrożyć i debugować aplikację desktopową app, musisz najpierw zainstalować swój app za pośrednictwem instalatora przed normalnym debugowaniem, aby skrót Start z identyfikatorem AUMID i CLSID był dostępny. Po zapoznaniu się ze skrótem Start można debugować przy użyciu F5 w programie Visual Studio.
Jeśli powiadomienia po prostu nie będą wyświetlane na pulpicie app (i nie są zgłaszane żadne wyjątki), prawdopodobnie oznacza to, że skrót startowy nie jest obecny (zainstaluj app plik za pośrednictwem instalatora) lub identyfikator AUMID użyty w kodzie nie jest zgodny z identyfikatorem AUMID w skrótie startowym.
Jeśli powiadomienia są wyświetlane, ale nie są utrwalane w Centrum akcji (znika po odrzuceniu wyskakującego okienka), oznacza to, że aktywacja COM nie została zaimplementowana poprawnie.
Jeśli zainstalowano zarówno spakowany, jak i rozpakowany pulpit app, należy pamiętać, że spakowany app zastąpi rozpakowany app podczas obsługi toast aktywacji. Oznacza to, że app powiadomienia z rozpakowanego app uruchomią zapakowany app po kliknięciu. Odinstalowanie spakowanego app spowoduje, że aktywacje zostaną przywrócone do stanu rozpakowanego app.
Jeśli otrzymasz HRESULT 0x800401f0 CoInitialize has not been called., upewnij się, że wywołasz CoInitialize(nullptr) w twojej app przed wywołaniem interfejsów API.
Jeśli otrzymasz HRESULT 0x8000000e A method was called at an unexpected time. podczas wywoływania interfejsów API Compat, prawdopodobnie oznacza to, że nie udało Ci się wywołać wymaganych metod rejestrowania (lub jeśli spakowany app nie jest obecnie uruchomiony app w kontekście opakowanym).
Jeśli wystąpi wiele błędów kompilacji unresolved external symbol, prawdopodobnie zapomniałeś dodać runtimeobject.lib do Dodatkowe Zależności w kroku 1 (lub dodałeś ją tylko do konfiguracji Debug, a nie do konfiguracji Release).
Obsługa starszych wersji systemu Windows
Jeśli obsługujesz system Windows 8.1 lub starszy, sprawdź w czasie wykonywania, czy używasz systemu Windows, zanim wywołasz jakiekolwiek DesktopNotificationManagerCompat API lub zanim wyślesz jakiekolwiek powiadomienia ToastGeneric.
System Windows 8 wprowadził toast powiadomienia, ale używał starszych toast szablonów, takich jak ToastText01. Aktywacja została obsługiwana przez nieutrwalane zdarzenie w pamięci Aktywowane w klasie ToastNotification, ponieważ były to tylko krótkie powiadomienia, które nie były utrwalane. System Windows 10 wprowadził interakcyjne toastyoraz Centrum Akcji, w którym powiadomienia są utrwalane przez wiele dni. Wprowadzenie Centrum akcji wymagało wprowadzenia aktywatora COM, aby toast można było aktywować kilka dni po jego utworzeniu.
| OS | ToastGeneric | Aktywacja COM | Starsze toast szablony |
|---|---|---|---|
| Windows 10 lub nowszy | Supported | Supported | Obsługiwane (ale nie aktywuje serwera COM) |
| Windows 8.1 / 8 | N/A | N/A | Supported |
| Windows 7 i niższe | N/A | N/A | N/A |
Aby sprawdzić, czy korzystasz z systemu Windows 10 lub nowszego, dołącz nagłówek <VersionHelpers.h> i sprawdź metodę IsWindows10OrGreater. Jeśli zwraca true, kontynuuj wywoływanie wszystkich metod opisanych w tej dokumentacji.
#include <VersionHelpers.h>
if (IsWindows10OrGreater())
{
// Running on Windows 10 or later, continue with sending toasts!
}
Znane problemy
NAPRAWIONO: App nie uzyskuje fokusu po kliknięciu toast: W kompilacjach 15063 i wcześniejszych prawa pierwszego planu nie były przekazywane do aplikacji po aktywowaniu serwera COM. Dlatego po prostu migałoby, gdy próbujesz przenieść je na pierwszy plan. Nie było obejścia tego problemu. Rozwiązaliśmy ten problem w kompilacjach 16299 lub nowszych.
Resources
Windows developer