Sdílet prostřednictvím


Rychlý průvodce: Push oznámení v sadě Windows App SDK

V tomto návodu pro rychlý začátek vytvoříte desktopovou aplikaci pro Windows, která odesílá a přijímá push oznámení pomocí sady Windows App SDK.

Prerequisites

Ukázková aplikace

Tento rychlý start vás provede přidáním podpory nabízených oznámení do vaší aplikace v sadě Windows App SDK 1.7. Podívejte se na podobný kód jako v tomto rychlém startu v ukázkových aplikacích nalezených na GitHubu. Nezapomeňte se podívat na větev s upřednostňovanou verzí sady Windows App SDK pro ukázky, které nejlépe odpovídají vašemu projektu.

Ukázky pro každou verzi sady Windows App SDK najdete také tak, že v úložišti ukázek vyberete větev verze.

Referenční informace k rozhraní API

Referenční dokumentaci k rozhraní API pro push notifikace viz Obor názvů Microsoft.Windows.PushNotifications.

Konfigurace identity aplikace v Azure Active Directory (AAD)

Push notifikace v Windows App SDK používají identity z Azure Active Directory (AAD). Při vyžádání identifikátoru URI kanálu WNS a při vyžádání přístupových tokenů k odesílání nabízených oznámení se vyžadují přihlašovací údaje Azure. Poznámka: Nepodporujeme pomocí nabízených oznámení sady Windows App SDK v Partnerském centru Microsoftu.

Krok 1: Vytvoření registrace aplikace AAD

Přihlaste se ke svému účtu Azure a vytvořte nový prostředek registrace aplikace AAD. Vyberte Nová registrace.

Krok 2: Zadejte název a vyberte možnost s více tenanty

  1. Zadejte název aplikace.

  2. Oznámení push vyžadují variantu s více nájemci, takže ji vyberte.

    1. Další informace o tenantech najdete v tématu Kdo se může přihlásit k vaší aplikaci?.
  3. Vyberte Zaregistrovat

  4. Poznamenejte si ID aplikace (klienta) , protože se jedná o Azure AppId , které budete používat při registraci aktivace a žádosti o přístupový token.

  5. Poznamenejte si ID vašeho adresáře (tenanta), protože se jedná o ID tenanta Azure , které budete používat při vyžádání přístupového tokenu.

    Important

    Registrace aplikace AAD tenanta poznamenejte si ID aplikace (klienta) a ID adresáře (tenanta) .

  6. Poznamenejte si ID objektu, protože je to vaše Azure ObjectId, které budete používat při žádosti o kanálový požadavek. Všimněte si, že se nejedná o ID objektu uvedené na stránce Základy . Pokud chcete najít správné ID objektu , klikněte na název aplikace v poli spravované aplikace v místním adresáři na stránce Essentials:

    Snímek obrazovky znázorňující možnost Spravovaná aplikace v místním adresáři na stránce Základy

    Snímek obrazovky s polem ID objektu

    Note

    K získání ID objektu se vyžaduje instanční objekt, pokud k vaší aplikaci není přidružený žádný, postupujte podle pokynů v jednom z následujících článků a vytvořte ho na webu Azure Portal nebo pomocí příkazového řádku:

    Použijte portál k vytvoření aplikace a servisního principála Azure AD, které mohou přistupovat k prostředkům

    Vytvoření instančního objektu s certifikátem pomocí Azure PowerShellu

Krok 3: Vytvoření tajného kódu pro registraci aplikace

Váš tajný klíč se použije společně s ID aplikace Azure nebo ID klienta při vyžádání přístupového tokenu k odesílání nabízených oznámení.

tajný klíč aplikace AAD

Přejděte na Certifikáty a tajné kódy a vyberte Nový tajný klíč klienta.

Important

Ujistěte se, že po vytvoření zkopírujete tajný klíč a uložíte ho do bezpečného umístění, jako je Azure Key Vault. Bude se zobrazovat jenom jednou po vytvoření.

Krok 4: Mapování názvu rodiny balíčků vaší aplikace na id aplikace Azure AppId

Pokud je vaše aplikace balíčkovaná (včetně zabalení s externím úložištěm), můžete pomocí tohoto postupu namapovat název rodiny balíčků vaší aplikace (PFN) a její ID aplikace Azure AppId.

Pokud je vaše aplikace zabalená aplikace Win32, vytvořte žádost o mapování rodiny balíčků (PFN) e-mailem Win_App_SDK_Push@microsoft.com s řádkem předmětu "Požadavek na mapování nabízených oznámení Windows App SDK Push" a textem "PFN: [vaš PFN], AppId: [vaše APPId], ObjectId: [vaše ObjectId]". Žádosti o mapování jsou dokončeny každý týden. Jakmile bude vaše žádost o mapování hotová, zobrazí se vám oznámení.

Jakmile budete mít Azure AppId, ObjectId a tajný klíč, můžete tyto přihlašovací údaje přidat do ukázkového kódu níže.

Nakonfigurujte svou aplikaci pro příjem push oznámení

Krok 1: Přidání sady Windows App SDK a požadovaných balíčků NuGet

Dále klikněte pravým tlačítkem na řešení v Průzkumníku řešení a vyberte Spravovat balíčky NuGet.

Ve Správci balíčků přidejte následující balíčky:

  • Microsoft.WindowsAppSDK (minimální verze 1.1.0)
  • Microsoft.Windows.SDK.BuildTools (minimálně verze 10.0.22000.194)
  • Microsoft.Windows.CppWinRT, (minimální verze 2.0.210930.14)
  • Microsoft.Windows.ImplementationLibrary, (minimální verze 1.0.210930.1)

Pokud ve svém projektu používáte sadu Windows App SDK poprvé a je zabalená s externím umístěním nebo rozbalením, inicializovat sadu Windows App SDK přidáním následující vlastnosti do souboru projektu:

<!-- your .vcxproj or .proj file -->
<PropertyGroup Label="Globals">
    <!-- Other properties -->
    <WindowsPackageType>None</WindowsPackageType>
</PropertyGroup>

nebo použijte rozhraní API bootstrapperu. Další podrobnosti najdete v tématu Použití modulu runtime sady Windows App SDK pro aplikace zabalené s externím umístěním nebo rozbalením .

Note

Pokud sada SDK není inicializována, aplikace se vyvolá System.Runtime.InteropServices.COMException (0x80040154): Class not registered (0x80040154 (REGDB_E_CLASSNOTREG)) a nespustí se.

Krok 2: Přidání oborů názvů

Dále přidejte obor názvů pro nabízená oznámení Microsoft.Windows.PushNotificationssady Windows App SDK .

#include <winrt/Microsoft.Windows.PushNotifications.h>

using namespace winrt::Microsoft::Windows::PushNotifications;

Pokud se zobrazí chyba "Nelze najít Microsoft.Windows.PushNotifications", znamená to pravděpodobně, že soubory hlaviček nebyly generovány. Pokud chcete tento problém vyřešit, ujistěte se, že máte nainstalované výše uvedené balíčky, zakomentujte příkazy include a using, které způsobují chybu, a znovu sestavte aplikaci, aby vygenerovala soubory hlaviček. Jakmile sestavení proběhne úspěšně, odkomentujte příkazy include a using a znovu sestavte projekt. Tím by se měla tato chyba vyřešit.

Krok 3: Přidání aktivátoru COM do manifestu aplikace

Important

Pokud je vaše aplikace rozbalený (tj. chybí identita balíčku za běhu), přejděte ke kroku 4: Registrace a reakce na nabízená oznámení při spuštění aplikace.

Pokud je vaše aplikace zabalená (včetně zabalení s externím umístěním): Otevřete Package.appxmanifest. Do elementu <Application> přidejte následující kód. Nahraďte hodnoty Id, Executable a DisplayName hodnotami specifickými pro vaši aplikaci.

<!--Packaged apps only-->
<!--package.appxmanifest-->

<Package
  ...
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
  ...
  <Applications>
    <Application>
      ...
      <Extensions>

        <!--Register COM activator-->    
        <com:Extension Category="windows.comServer">
          <com:ComServer>
              <com:ExeServer Executable="SampleApp\SampleApp.exe" DisplayName="SampleApp" Arguments="----WindowsAppRuntimePushServer:">
                <com:Class Id="[Your app's Azure AppId]" DisplayName="Windows App SDK Push" />
            </com:ExeServer>
          </com:ComServer>
        </com:Extension>
    
      </Extensions>
    </Application>
  </Applications>
 </Package>    

Note

Příklad dokončené třídy C++ pro tento příklad lze najít po kroku 5. Kroky 4 a 5 obsahují podrobné pokyny k přidání jednotlivých kroků v posledním příkladu.

Krok 4: Registrace a reakce na nabízená oznámení při spuštění aplikace

Aktualizujte metodu main() aplikace tak, aby přidala následující:

  1. Zaregistrujte aplikaci pro příjem push oznámení voláním PushNotificationManager::Default().Register().
  2. Zkontrolujte zdroj žádosti o aktivaci voláním AppInstance::GetCurrent(). GetActivatedEventArgs(). Pokud byla aktivace spuštěna z push oznámení, odpovězte na základě datové části oznámení.

Important

Musíte volat PushNotificationManager::D efault(). Zaregistrujte před voláním AppInstance.GetCurrent.GetActivatedEventArgs.

Přidání obslužných rutin událostí popředí

Pokud chcete zpracovat událost v popředí, zaregistrujte obslužnou rutinu pro PushNotificationManager.PushReceived.

Important

Před voláním PushNotificationManager.Register() musíte také zaregistrovat všechny obslužné rutiny událostí PushNotificationManager.PushReceived . Jinak se vyvolá následující výjimka modulu runtime:

System.Runtime.InteropServices.COMException: Element not found. Must register event handlers before calling Register().

Přidání kontroly PushNotificationManager::IsSupported()

Dále přidejte kontrolu, jestli jsou rozhraní API PushNotification podporována pomocí PushNotificationManager.IsSupported(). Pokud ne, doporučujeme použít dotazování nebo vlastní implementaci soketů.

Teď, když je potvrzená podpora nabízených oznámení, přidejte chování na základě PushNotificationReceivedEventArgs.

Krok 5: Vyžádání identifikátoru URI kanálu WNS a jeho registrace na serveru WNS

Identifikátory URI kanálu WNS jsou koncové body HTTP pro odesílání nabízených oznámení. Každý klient musí požádat o identifikátor URI kanálu a zaregistrovat ho u serveru WNS, aby dostával nabízená oznámení.

Note

Identifikátory URI kanálu WNS vyprší po 30 dnech.

auto channelOperation{ PushNotificationManager::Default().CreateChannelAsync(winrt::guid("[Your app's Azure ObjectID]")) };

Pokud sledujete kód kurzu, přidejte své ID objektu Azure sem:

// To obtain an AAD RemoteIdentifier for your app,
// follow the instructions on https://learn.microsoft.com/azure/active-directory/develop/quickstart-register-app
winrt::guid remoteId{ "00000000-0000-0000-0000-000000000000" }; // Replace this with your own Azure ObjectId

PushNotificationManager se pokusí vytvořit identifikátor URI kanálu a automaticky to zkusí znovu po dobu maximálně 15 minut. Vytvořte obslužnou rutinu události, která bude čekat na dokončení volání. Po dokončení volání zaregistrujte identifikátor URI na serveru WNS.

Příklad kódu

#include <iostream>
#include <winrt/Microsoft.Windows.PushNotifications.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Microsoft.Windows.AppLifecycle.h>
#include <winrt/Windows.ApplicationModel.Background.h>
#include <wil/cppwinrt.h>
#include <wil/result.h>

using namespace winrt::Microsoft::Windows::PushNotifications;
using namespace winrt::Windows::Foundation;
using namespace winrt::Microsoft::Windows::AppLifecycle;

// To obtain an AAD RemoteIdentifier for your app,
// follow the instructions on https://learn.microsoft.com/azure/active-directory/develop/quickstart-register-app
winrt::guid remoteId{ "00000000-0000-0000-0000-000000000000" }; // Replace this with your own Azure ObjectId

winrt::Windows::Foundation::IAsyncOperation<PushNotificationChannel> RequestChannelAsync()
{
    auto channelOperation = PushNotificationManager::Default().CreateChannelAsync(remoteId);

    // Set up the in-progress event handler
    channelOperation.Progress(
        [](auto&& sender, auto&& args)
        {
            if (args.status == PushNotificationChannelStatus::InProgress)
            {
                // This is basically a noop since it isn't really an error state
                std::cout << "Channel request is in progress." << std::endl << std::endl;
            }
            else if (args.status == PushNotificationChannelStatus::InProgressRetry)
            {
                LOG_HR_MSG(
                    args.extendedError,
                    "The channel request is in back-off retry mode because of a retryable error! Expect delays in acquiring it. RetryCount = %d",
                    args.retryCount);
            }
        });

    auto result = co_await channelOperation;

    if (result.Status() == PushNotificationChannelStatus::CompletedSuccess)
    {
        auto channelUri = result.Channel().Uri();

        std::cout << "channelUri: " << winrt::to_string(channelUri.ToString()) << std::endl << std::endl;

        auto channelExpiry = result.Channel().ExpirationTime();

        // Caller's responsibility to keep the channel alive
        co_return result.Channel();
    }
    else if (result.Status() == PushNotificationChannelStatus::CompletedFailure)
    {
        LOG_HR_MSG(result.ExtendedError(), "We hit a critical non-retryable error with channel request!");
        co_return nullptr;
    }
    else
    {
        LOG_HR_MSG(result.ExtendedError(), "Some other failure occurred.");
        co_return nullptr;
    }

};

PushNotificationChannel RequestChannel()
{
    auto task = RequestChannelAsync();
    if (task.wait_for(std::chrono::seconds(300)) != AsyncStatus::Completed)
    {
        task.Cancel();
        return nullptr;
    }

    auto result = task.GetResults();
    return result;
}

void SubscribeForegroundEventHandler()
{
    winrt::event_token token{ PushNotificationManager::Default().PushReceived([](auto const&, PushNotificationReceivedEventArgs const& args)
    {
        auto payload{ args.Payload() };

        std::string payloadString(payload.begin(), payload.end());
        std::cout << "\nPush notification content received in the FOREGROUND: " << payloadString << std::endl;
    }) };

    std::cout << "Push notification foreground event handler registered." << std::endl;
}

int main()
{
    // Set up an event handler, so we can receive notifications in the foreground while the app is running.
    // You must register notification event handlers before calling Register(). Otherwise, the following runtime
    // exception will be thrown: System.Runtime.InteropServices.COMException: 'Element not found. Must register
    // event handlers before calling Register().'
    SubscribeForegroundEventHandler();

    // Register the app for push notifications.
    PushNotificationManager::Default().Register();

    auto args{ AppInstance::GetCurrent().GetActivatedEventArgs() };
    switch (args.Kind())
    {
        case ExtendedActivationKind::Launch:
        {
            std::cout << "App launched by user or from the debugger." << std::endl;
            if (PushNotificationManager::IsSupported())
            {
                std::cout << "Push notifications are supported on this device." << std::endl;

                // Request a WNS Channel URI which can be passed off to an external app to send notifications to.
                // The WNS Channel URI uniquely identifies this app for this user and device.
                PushNotificationChannel channel{ RequestChannel() };
                if (!channel)
                {
                    std::cout << "\nThere was an error obtaining the WNS Channel URI" << std::endl;

                    if (remoteId == winrt::guid{ "00000000-0000-0000-0000-000000000000" })
                    {
                        std::cout << "\nThe ObjectID has not been set. Refer to the readme file accompanying this sample\nfor the instructions on how to obtain and setup an ObjectID" << std::endl;
                    }
                }

                std::cout << "\nPress 'Enter' at any time to exit App." << std::endl;
                std::cin.ignore();
            }
            else
            {
                std::cout << "Push notifications are NOT supported on this device." << std::endl;
                std::cout << "App implements its own custom socket here to receive messages from the cloud since Push APIs are unsupported." << std::endl;
                std::cin.ignore();
            }
        }
        break;

        case ExtendedActivationKind::Push:
        {
            std::cout << "App activated via push notification." << std::endl;
            PushNotificationReceivedEventArgs pushArgs{ args.Data().as<PushNotificationReceivedEventArgs>() };

            // Call GetDeferral to ensure that code runs in low power
            auto deferral{ pushArgs.GetDeferral() };

            auto payload{ pushArgs.Payload() };

            // Do stuff to process the raw notification payload
            std::string payloadString(payload.begin(), payload.end());
            std::cout << "\nPush notification content received in the BACKGROUND: " << payloadString.c_str() << std::endl;
            std::cout << "\nPress 'Enter' to exit the App." << std::endl;

            // Call Complete on the deferral when finished processing the payload.
            // This removes the override that kept the app running even when the system was in a low power mode.

            deferral.Complete();
            std::cin.ignore();
        }
        break;

        default:
            std::cout << "\nUnexpected activation type" << std::endl;
            std::cout << "\nPress 'Enter' to exit the App." << std::endl;
            std::cin.ignore();
            break;
    }
}

Krok 6: Sestavení a instalace aplikace

Pomocí sady Visual Studio sestavte a nainstalujte aplikaci. V Průzkumníku řešení klikněte pravým tlačítkem myši na soubor řešení a vyberte Nasadit. Visual Studio sestaví vaši aplikaci a nainstaluje ji do počítače. Aplikaci můžete spustit tak, že ji spustíte pomocí nabídky Start nebo ladicího programu sady Visual Studio.

Konzola kódu kurzu bude vypadat takto:

funkční ukázková konzola

K odeslání nabízeného oznámení do aplikace budete potřebovat token.

Odeslání nabízeného oznámení do aplikace

V tuto chvíli je veškerá konfigurace dokončená a server WNS může odesílat nabízená oznámení klientským aplikacím. V následujících krocích se odkazujte na hlavičky požadavků a odpovědí push notifikačního serveru a pro bližší informace.

Krok 1: Vyžádání přístupového tokenu

Pokud chcete odeslat nabízené oznámení, musí server WNS nejprve požádat o přístupový token. Odešlete požadavek HTTP POST s ID tenanta Azure, Azure AppId a tajným kódem. Informace o načtení ID tenanta Azure a ID aplikace Azure najdete v tématu Získání hodnot ID tenanta a aplikace pro přihlášení.

Ukázkový požadavek HTTP:

POST /{tenantID}/oauth2/v2.0/token Http/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 160

grant_type=client_credentials&client_id=<Azure_App_Registration_AppId_Here>&client_secret=<Azure_App_Registration_Secret_Here>&scope=https://wns.windows.com/.default/

Ukázkový požadavek jazyka C#:

//Sample C# Access token request
var client = new RestClient("https://login.microsoftonline.com/{tenantID}/oauth2/v2.0");
var request = new RestRequest("/token", Method.Post);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", "[Your app's Azure AppId]");
request.AddParameter("client_secret", "[Your app's secret]");
request.AddParameter("scope", "https://wns.windows.com/.default");
RestResponse response = await client.ExecutePostAsync(request);
Console.WriteLine(response.Content);

Pokud je vaše žádost úspěšná, obdržíte odpověď, která obsahuje váš token v poli access_token .

{
    "token_type":"Bearer",
    "expires_in":"86399",
    "ext_expires_in":"86399",
    "expires_on":"1653771789",
    "not_before":"1653685089",
    "access_token":"[your access token]"
}

Krok 2. Odeslání nezpracovaného oznámení

Vytvořte požadavek HTTP POST obsahující přístupový token, který jste získali v předchozím kroku, a obsah nabízeného oznámení, které chcete odeslat. Obsah push oznámení bude doručen do aplikace.

POST /?token=[The token query string parameter from your channel URL. E.g. AwYAAABa5cJ3...] HTTP/1.1
Host: dm3p.notify.windows.com
Content-Type: application/octet-stream
X-WNS-Type: wns/raw
Authorization: Bearer [your access token]
Content-Length: 46

{ Sync: "Hello from the Contoso App Service" }
var client = new RestClient("[Your channel URL. E.g. https://wns2-by3p.notify.windows.com/?token=AwYAAABa5cJ3...]");
var request = new RestRequest();
request.Method = Method.Post; 
request.AddHeader("Content-Type", "application/octet-stream");
request.AddHeader("X-WNS-Type", "wns/raw");
request.AddHeader("Authorization", "Bearer [your access token]");
request.AddBody("Notification body");
RestResponse response = await client.ExecutePostAsync(request);");

Krok 3: Odeslání oznámení o cloudové zdrojové aplikaci

Pokud vás zajímá jenom odesílání nezpracovaných oznámení, ignorujte tento krok. Pokud chcete odeslat oznámení aplikace z cloudu, známé také jako oznámení typu toast, nejprve postupujte podle Rychlý start: Oznámení aplikací v sadě Windows App SDK. Oznámení aplikací můžou být nabízená (odesílaná z cloudu) nebo místně odesílaná. Odeslání oznámení aplikace zdrojového do cloudu se podobá odeslání nezpracovaného oznámení v kroku 2s výjimkou záhlaví typu X-WNS typu je toast, Content-Type je text/xmla obsah obsahuje datovou část XML oznámení aplikace. Další informace o tom, jak sestavit datovou část XML, najdete v tématu XML schéma oznámení.

Vytvořte požadavek HTTP POST, který obsahuje váš přístupový token a obsah oznámení cloudové aplikace, které chcete odeslat. Obsah push oznámení bude doručen do aplikace.

POST /?token=AwYAAAB%2fQAhYEiAESPobjHzQcwGCTjHu%2f%2fP3CCNDcyfyvgbK5xD3kztniW%2bjba1b3aSSun58SA326GMxuzZooJYwtpgzL9AusPDES2alyQ8CHvW94cO5VuxxLDVzrSzdO1ZVgm%2bNSB9BAzOASvHqkMHQhsDy HTTP/1.1
Host: dm3p.notify.windows.com
Content-Type: text/xml
X-WNS-Type: wns/toast
Authorization: Bearer [your access token]
Content-Length: 180

<toast><visual><binding template="ToastGeneric"><text>Example cloud toast notification</text><text>This is an example cloud notification using XML</text></binding></visual></toast>
var client = new RestClient("https://dm3p.notify.windows.com/?token=AwYAAAB%2fQAhYEiAESPobjHzQcwGCTjHu%2f%2fP3CCNDcyfyvgbK5xD3kztniW%2bjba1b3aSSun58SA326GMxuzZooJYwtpgzL9AusPDES2alyQ8CHvW94cO5VuxxLDVzrSzdO1ZVgm%2bNSB9BAzOASvHqkMHQhsDy");
client.Timeout = -1;

var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "text/xml");
request.AddHeader("X-WNS-Type", "wns/toast");
request.AddHeader("Authorization", "Bearer <AccessToken>");
request.AddParameter("text/xml", "<toast><visual><binding template=\"ToastGeneric\"><text>Example cloud toast notification</text><text>This is an example cloud notification using XML</text></binding></visual></toast>",  ParameterType.RequestBody);
Console.WriteLine(response.Content);

Resources