Dela via


Snabbstart: Push-meddelanden i Windows App SDK

I den här snabbstarten skapar du ett Windows-skrivbordsprogram som skickar och tar emot push-meddelanden med hjälp av Windows App SDK.

Prerequisites

Exempelapp

Den här snabbstarten går igenom hur du lägger till stöd för push-meddelanden i din app i Windows App SDK 1.7. Se liknande kod som den här snabbstarten i exempelapparna som finns på GitHub. Se till att kolla in grenen med den önskade versionen av Windows App SDK för de exempel som bäst matchar projektet.

Du kan också hitta exempel för varje version av Windows App SDK genom att välja en versionsgren i exempellagringsplatsen.

API-referensen

Api-referensdokumentation för push-meddelanden finns i Namnrymden Microsoft.Windows.PushNotifications.

Konfigurera appens identitet i Azure Active Directory (AAD)

Push-meddelanden i Windows App SDK använder identiteter från Azure Active Directory (AAD). Azure-autentiseringsuppgifter krävs när du begär en WNS Channel-URI och när du begär åtkomsttoken för att skicka push-meddelanden. Obs: Vi stödjer INTE användning av push-aviseringar för Windows App SDK i samband med Microsoft Partner Center.

Steg 1: Skapa en AAD-appregistrering

Logga in på ditt Azure-konto och skapa en ny AAD-Appregistrering-resurs. Välj Ny registrering.

Steg 2: Ange ett namn och välj ett alternativ för flera klientorganisationer

  1. Ange ett appnamn.

  2. Push-meddelanden kräver alternativet för flera hyresgäster, så välj det.

    1. Mer information om klienter finns i Vem kan logga in på din app?.
  3. Välj Registrera

  4. Anteckna ditt program-ID (klient)-ID eftersom det här är ditt Azure AppId som du kommer att använda under aktiveringsregistrering och begäran om åtkomsttoken.

  5. Anteckna ditt Directory ID (klientorganisation)eftersom det här är din Azure TenantId som du kommer att använda när du begär ett åtkomsttoken.

    Important

    AAD App Registration Tenant Anteckna ditt program-ID (klient)-ID och Directory-ID (klientorganisation).

  6. Anteckna ditt objekt-ID eftersom det här är ditt Azure ObjectId som du kommer att använda när du begär en kanalbegäran. Observera att detta INTE är objekt-ID:t som visas på sidan Essentials . Om du i stället vill hitta rätt objekt-ID klickar du på appnamnet i fältet Hanterat program i lokal katalog på sidan Essentials :

    Skärmbild som visar alternativet Hanterat program i lokal katalog på sidan Essentials

    Skärmbild som visar fältet Objekt-ID

    Note

    Ett tjänstehuvudnamn krävs för att hämta ett objekt-ID. Om det inte finns något som är associerat med din app, följer du stegen i någon av följande artiklar för att skapa ett i Azure-portalen eller med hjälp av kommandoraden.

    Använd portalen för att skapa en Azure AD-program och ett tjänsthuvudnamn som kan komma åt resurser

    Använda Azure PowerShell för att skapa ett huvudnamn för tjänsten med ett certifikat

Steg 3: Skapa en hemlighet för din appregistrering

Din hemlighet används tillsammans med ditt Azure AppId/ClientId när du begär en åtkomsttoken för att skicka push-meddelanden.

AAD-apphemlighet

Gå till Certifikat och hemligheter och välj Ny klienthemlighet.

Important

Se till att du kopierar din hemlighet när den har skapats och lagrar den på en säker plats, till exempel Azure Key Vault. Den kan bara visas en gång direkt när den har skapats.

Steg 4: Mappa appens paketfamiljenamn till dess Azure AppId

Om din app är paketerad (inklusive paketerad med en extern plats) kan du använda det här flödet för att mappa appens paketfamiljenamn (PFN) och dess Azure AppId.

Om din app är en paketerad Win32-app skapar du en PFN-mappningsbegäran (Package Family Name) genom att Win_App_SDK_Push@microsoft.com skicka e-post med ämnesraden "Windows App SDK Push Notifications Mapping Request" och brödtexten "PFN: [your PFN]", AppId: [your APPId], ObjectId: [your ObjectId]. Mappningsbegäranden slutförs varje vecka. Du meddelas när din mappningsbegäran har slutförts.

När du har ditt Azure AppId, ObjectId och din hemlighet kan du lägga till dessa autentiseringsuppgifter i exempelkoden nedan.

Konfigurera din app för att ta emot push-meddelanden

Steg 1: Lägg till Windows App SDK och nödvändiga NuGet-paket

Högerklicka sedan på lösningen i Solution Explorer och välj Hantera NuGet-paket.

Lägg till följande paket i Pakethanteraren:

  • Microsoft.WindowsAppSDK (lägsta version 1.1.0)
  • Microsoft.Windows.SDK.BuildTools (lägsta version 10.0.22000.194)
  • Microsoft.Windows.CppWinRT, (lägsta version 2.0.210930.14)
  • Microsoft.Windows.ImplementationLibrary (lägsta version 1.0.210930.1)

Om det här är första gången du använder Windows App SDK i projektet och det paketeras med extern plats eller packas upp initierar du Windows App SDK genom att lägga till följande egenskap i projektfilen:

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

eller använd bootstrapper-API:et. Mer information finns i Använda Windows App SDK-körningen för appar som paketeras med extern plats eller packas upp .

Note

Om SDK:et inte initieras kommer appen att generera System.Runtime.InteropServices.COMException (0x80040154): Class not registered (0x80040154 (REGDB_E_CLASSNOTREG)) och kommer inte att köras.

Steg 2: Lägg till namnområden

Lägg sedan till namnområdet för Push-meddelanden Microsoft.Windows.PushNotificationsför Windows App SDK .

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

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

Om du får felet "Det går inte att hitta Microsoft.Windows.PushNotifications" innebär det förmodligen att huvudfilerna inte har genererats. Lös problemet genom att se till att paketen ovan är installerade, kommentera ut instruktionen include och using som orsakar felet och återskapa programmet för att generera huvudfilerna. När bygget har slutförts avkommenterar du inkludera och använda instruktioner och återskapa projektet. Detta bör lösa felet.

Steg 3: Lägg till COM-aktivatorn i appens manifest

Important

Om din app är uppackad (dvs. den saknar paketidentitet vid körning) går du vidare till Steg 4: Registrera dig för och svara på push-meddelanden vid appstart.

Om din app är paketerad (inklusive paketerad med extern lagringsplats): Öppna din Package.appxmanifest. Lägg till följande i elementet <Application> . IdErsätt värdena , Executableoch DisplayName med de som är specifika för din app.

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

Ett exempel på den slutförda C++-klassen för det här exemplet finns efter steg 5. Steg 4 och 5 innehåller stegvis vägledning för att lägga till varje del i det sista exemplet.

Steg 4: Registrera dig för och svara på push-meddelanden vid appstart

Uppdatera appens main() metod för att lägga till följande:

  1. Registrera din app för att ta emot push-meddelanden genom att anropa PushNotificationManager::D efault(). Registrera().
  2. Kontrollera källan för aktiveringsbegäran genom att anropa AppInstance::GetCurrent(). GetActivatedEventArgs(). Om aktiveringen utlöstes från ett push-meddelande svarar du baserat på meddelandets nyttolast.

Important

Du måste anropa PushNotificationManager::D efault(). Registrera innan du anropar AppInstance.GetCurrent.GetActivatedEventArgs.

Lägga till händelsehanterare för förgrund

Om du vill hantera en händelse i förgrunden registrerar du en hanterare för PushNotificationManager.PushReceived.

Important

Du måste också registrera alla PushNotificationManager.PushReceived-händelsehanterare innan du anropar PushNotificationManager.Register(). I annat fall utlöses följande körningsundatag:

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

Lägg till kontrollen PushNotificationManager::IsSupported()

Lägg sedan till en kontroll om PushNotification-API:erna stöds med PushNotificationManager.IsSupported(). Annars rekommenderar vi att du använder avsökning eller din egen implementering av anpassade socketar.

Nu när det finns bekräftat stöd för push-meddelanden lägger du till beteende baserat på PushNotificationReceivedEventArgs.

Steg 5: Begär en WNS Channel-URI och registrera den med WNS-servern

WNS-kanal-URI:er är HTTP-slutpunkterna för att skicka push-meddelanden. Varje klient måste begära en kanal-URI och registrera den med WNS-servern för att ta emot push-meddelanden.

Note

WNS-kanal-URI:er upphör att gälla efter 30 dagar.

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

Om du följer självstudiekoden lägger du till ditt Azure-objekt-ID här:

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

PushNotificationManager- försöker skapa en kanal-URI och försöker igen automatiskt i högst 15 minuter. Skapa en händelsehanterare som väntar tills anropet har slutförts. När anropet är klart registrerar du URI:n med WNS-servern om det lyckades.

Exempelkod

#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://free.blessedness.top/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;
    }
}

Steg 6: Skapa och installera din app

Använd Visual Studio för att skapa och installera din app. Högerklicka på lösningsfilen i Solution Explorer och välj Distribuera. Visual Studio skapar din app och installerar den på datorn. Du kan köra appen genom att starta den via Start-menyn eller Visual Studio-felsökningsprogrammet.

Självstudiekodens konsol ser ut så här:

arbetsexempelkonsol

Du behöver token för att skicka ett push-meddelande till din app.

Skicka ett push-meddelande till din app

Nu är all konfiguration klar och WNS-servern kan skicka push-meddelanden till klientappar. I följande steg se push-meddelandeserverns begärans- och svarshuvuden för mer information.

Steg 1: Begär en åtkomsttoken

För att skicka ett push-meddelande måste WNS-servern först begära en åtkomsttoken. Skicka en HTTP POST-begäran med ditt Azure TenantId, Azure AppId och din hemlighet. Information om hur du hämtar Azure TenantId och Azure AppId finns i Hämta klient- och app-ID-värden för inloggning.

HTTP-exempelbegäran:

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/

C#-exempelbegäran:

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

Om din begäran lyckas får du ett svar som innehåller din token i fältet access_token .

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

Steg 2. Skicka en råavisering

Skapa en HTTP POST-begäran som innehåller den åtkomsttoken som du fick i föregående steg och innehållet i push-meddelandet som du vill skicka. Innehållet i push-meddelandet levereras till appen.

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

Steg 3: Skicka ett meddelande från en molnbaserad app

Om du bara är intresserad av att skicka råa meddelanden bortser du från det här steget. Om du vill skicka ett meddelande från en molnbaserad app, även känt som ett push-popup-meddelande, följer du först Snabbstart: Appaviseringar i Windows App SDK. Appaviseringar kan antingen skickas (skickas från molnet) eller skickas lokalt. Att skicka ett meddelande från en molnbaserad app liknar att skicka ett rådatameddelande i steg 2, förutom att rubriken X-WNS-Type är toast, Content-Type är text/xmloch innehållet innehåller XML-nyttolasten för appmeddelanden. Mer information om hur du skapar XML-nyttolasten finns i XML-schema för meddelanden .

Skapa en HTTP POST-begäran som innehåller din åtkomsttoken och innehållet i det molnbaserade appmeddelande som du vill skicka. Innehållet i push-meddelandet levereras till appen.

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