Avvio rapido: notifiche push in Windows App SDK

In questa guida introduttiva si creerà un'applicazione desktop di Windows che invia e riceve notifiche push usando Windows App SDK.

Prerequisiti

Esempio di app

Questa guida introduttiva illustra come aggiungere il supporto delle notifiche push all'app. Vedere il codice di esempio di questa guida introduttiva nel contesto nelle app di esempio disponibili in GitHub.

Informazioni di riferimento sulle API

Per la documentazione di riferimento sulle API per le notifiche push, vedere Spazio dei nomi Microsoft.Windows.PushNotifications.

Configurare l'identità dell'app in Azure Active Directory (AAD)

Le notifiche push in Windows App SDK usano le identità di Azure Active Directory (AAD). Le credenziali di Azure sono necessarie quando si richiede un URI del canale WNS e quando si richiedono token di accesso per inviare notifiche push. Nota: non si supporta l'uso di notifiche push di Windows App SDK con il Centro per i partner Microsoft.

Fase 1: crea una registrazione dell'app AAD

Accedere all'account Azure e creare una nuova risorsa registrazione app AAD. Seleziona Nuova registrazione.

Fase 2: specificare un nome e selezionare un'opzione multi-tenant

  1. Immetti un nome per l'app.

  2. Le notifiche push richiedono l'opzione multi-tenant, quindi selezionare questa opzione.

    1. Per altre informazioni sui tenant, vedere Chi può accedere all'app?
  3. Selezionare Registra

  4. Prendere nota dell'ID applicazione (client) ID, poiché si tratta di Azure AppId che verrà usato durante la registrazione dell'attivazione e la richiesta di token di accesso.

  5. Prendere nota dell'ID Directory (tenant), poiché si tratta di Azure TenantId che verrà usato quando si richiede un token di accesso.

    Importante

    AAD App Registration Tenant Prendere nota dell'ID Applicazione (client) e dell'ID Directory (tenant).

  6. Prendere nota dell'ID oggetto, in quanto si tratta di Azure ObjectId che verrà usato quando si richiede una richiesta di canale. Si noti che non si tratta dell'ID oggetto elencato nella pagina Essentials. Per trovare invece l'ID oggetto corretto, fare clic sul nome dell'app nel riquadro Applicazione gestita nella directory locale alla pagina Essentials:

    Screenshot showing the Managed application in local directory option on the Essentials page

    Screenshot showing the Object ID field

    Nota

    Per ottenere un ID oggetto è necessaria una entità servizio; se non è associata all'app, seguire la procedura descritta in uno degli articoli seguenti per crearne uno nel portale di Azure o usando la riga di comando:

    usare il portale per creare un'applicazione Azure AD e un'entità servizio che possano accedere alle risorse

    Usare Azure PowerShell per creare un'entità servizio con un certificato

Fase 3: Creare un segreto per la registrazione dell'app

Il segreto verrà usato insieme all'app Azure Id/ClientId quando si richiede un token di accesso per inviare notifiche push.

AAD App Secret

Selezionare Certificati & segreti, poi Nuovo segreto client.

Importante

Assicurarsi di copiare il segreto una volta creato e archiviarlo in una posizione sicura, ad esempio Azure Key Vault. Sarà visualizzabile solo una volta subito dopo la creazione.

Fase 4: Eseguire il mapping del nome della famiglia di pacchetti dell'app al relativo AppId Azure

Importante

Windows Push Notification Service (WNS) è ora integrato con il portale di Azure. La nuova esperienza di registrazione è disponibile in anteprima. Se si tratta di un'app inclusa nel pacchetto (inclusa la posizione esterna in pacchetto), è possibile usare questo flusso per eseguire il mapping del nome della famiglia di pacchetti (PFN) dell'app e del relativo app Azure Id.

Se l'app è un'app Win32 inclusa nel pacchetto, richiedere l'accesso alla nuova esperienza di Anteprima inviando un messaggio di posta elettronica Win_App_SDK_Push@microsoft.com con riga dell'oggetto "richiesta di notifiche push Windows App SDK" e corpo dell'email "Sottoscrizione di Azure: [l'ID di sottoscrizione Azure]". Le richieste vengono completate su base settimanale. Una volta completata la richiesta di mapping, si riceverà una notifica.

Configura l'app per ricevere notifiche push

Passaggio 1: Aggiungere le dichiarazioni dello spazio dei nomi

Aggiungere lo spazio dei nomi per notifiche push Windows App SDK Microsoft.Windows.PushNotifications.

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

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

Fase 2: aggiungere l'attivatore COM al manifesto dell'app

Importante

Se l'app non è inclusa nel pacchetto ( ovvero manca l'identità del pacchetto in fase di esecuzione), passare alla Fase 3: registrazione e risposta alle notifiche push all'avvio dell'app.

Se l'app è inclusa in un pacchetto con percorso esterno: aprire Package.appxmanifest. Nell'elemento <Application> aggiungere il codice HTML seguente. Sostituire i Idvalori , Executablee DisplayName con quelli specifici dell'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>    

Fase 3: registrazione e risposta alle notifiche push all'avvio dell'app

Aggiornare il metodo dell'app main() per aggiungere quanto segue:

  1. Registrare l'app per ricevere notifiche push richiedendo PushNotificationManager::D efault(). Register().
  2. Controllare l'origine della richiesta di attivazione richiedendo AppInstance::GetCurrent(). GetActivatedEventArgs(). Se l'attivazione è stata attivata da una notifica push, rispondere in base al payload della notifica.

Importante

È necessario chiamare PushNotificationManager::Default().Register prima di richiedere AppInstance.GetCurrent.GetActivatedEventArgs.

L'esempio seguente proviene dall'app in pacchetto di esempio disponibile in GitHub.

// cpp-console.cpp
#include "pch.h"
#include <iostream>
#include <winrt/Microsoft.Windows.PushNotifications.h>
#include <winrt/Microsoft.Windows.AppLifecycle.h>
#include <winrt/Windows.Foundation.h>
#include <wil/result.h>
#include <wil/cppwinrt.h>


using namespace winrt;
using namespace Windows::Foundation;

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

winrt::guid remoteId{ "7edfab6c-25ae-4678-b406-d1848f97919a" }; // Replace this with your own Azure ObjectId



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

int main()
{
    // Setup an event handler, so we can receive notifications in the foreground while the app is running.
    SubscribeForegroundEventHandler();

    PushNotificationManager::Default().Register();

    auto args{ AppInstance::GetCurrent().GetActivatedEventArgs() };
    switch (args.Kind())
    {
        // When it is launched normally (by the users, or from the debugger), the sample requests a WNS Channel URI and
        // displays it, then waits for notifications. This user can take a copy of the WNS Channel URI and use it to send
        // notifications to the sample
        case ExtendedActivationKind::Launch:
        {
            // Checks to see if push notifications are supported. Certain self-contained apps may not support push notifications by design
            if (PushNotificationManager::IsSupported())
            {
                // 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
            {
                // App implements its own custom socket here to receive messages from the cloud since Push APIs are unsupported.
            }
        }
        break;

        // When it is activated from a push notification, the sample only displays the notification.
        // It doesn’t register for foreground activation of perform any other actions
        // because background activation is meant to let app perform only small tasks in order to preserve battery life.
        case ExtendedActivationKind::Push:
        {
            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;
    }

    // We do not call PushNotificationManager::UnregisterActivator
    // because then we wouldn't be able to receive background activations, once the app has closed.
    // Call UnregisterActivator once you don't want to receive push notifications anymore.
}

Fase 4: Richiesta di un URI del canale WNS e registrazione con il server WNS

Gli URI del canale WNS sono gli endpoint HTTP per l'invio di notifiche push. Ogni client deve richiedere un URI del canale e registrarlo con il server WNS per ricevere notifiche push.

Nota

Gli URI del canale WNS scadono dopo 30 giorni.

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

PushNotificationManager tenterà di creare un URI del canale, riprovando automaticamente per non più di 15 minuti. Creare un gestore eventi per attendere il completamento della chiamata. Al termine della chiamata, in caso di esito positivo, registrare l'URI con il server WNS.

// cpp-console.cpp

winrt::Windows::Foundation::IAsyncOperation<PushNotificationChannel> RequestChannelAsync()
{
    // To obtain an AAD RemoteIdentifier for your app,
    // follow the instructions on https://learn.microsoft.com/azure/active-directory/develop/quickstart-register-app
    auto channelOperation = PushNotificationManager::Default().CreateChannelAsync(remoteId);

    // Setup the inprogress 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;
}

Fase 5: compilazione e installazione dell'app

Usare Visual Studio per compilare e installare la propria app. Da Esplora soluzioni, fare clic con il pulsante destro del mouse, quindi selezionare Distribuisci. Visual Studio compilerà l'app e la installerà nel computer. È possibile eseguire l'app avviandola tramite il menu Start o il debugger di Visual Studio.

Invia una notifica push all'app

A questo punto, tutte le configurazioni sono complete e il server WNS può inviare notifiche push alle app client. Nei passaggi seguenti fare riferimento alle Intestazioni di richiesta e risposta del server di notifica push per ulteriori dettagli..

Fase 1: richiesta di un token di accesso

Per inviare una notifica push, il server WNS deve prima richiedere un token di accesso. Inviare una richiesta HTTP POST con Il tenantId di Azure, app Azure Id e il segreto. Per informazioni sul recupero di Azure TenantId e app Azure Id, vedere Ottenere i valori di ID tenant e app per l'accesso.

Richiesta di campione 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/

Richiesta di campione 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);

Se la richiesta ha esito positivo, si riceverà una risposta contenente il token nel campo access_token .

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

Passaggio 2. Invia una notifica non elaborata

Creare una richiesta HTTP POST contenente il token di accesso ottenuto nel passaggio precedente e il contenuto della notifica push da inviare. Il contenuto della notifica push verrà recapitato all'app.

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

Fase 3: invio di una notifica dell'app di origine cloud

Se si è interessati solo all'invio di notifiche non elaborate, ignorare questo passaggio. Per inviare una notifica dell'app con origine cloud, nota anche come avvio push toast, seguire in primo luogo Avvio rapido: Notifiche dell'app in Windows App SDK. Le notifiche delle app possono essere push (inviate dal cloud) o inviate localmente. L'invio di una notifica dell'app con origine cloud è simile all'invio di una notifica non elaborata nella fase 2, a eccezione del fatto che l'intestazione del Tipo X-WNS è toast, Tipo di contenuto è text/xml e il contenuto contiene il payload XML di notifica dell'app. Per altre informazioni su come costruire il payload XML, vedere Schema XML notifiche per ulteriori informazioni su come costruire il payload XML.

Creare una richiesta HTTP POST contenente il token di accesso e il contenuto della notifica dell'app di origine cloud da inviare. Il contenuto della notifica push verrà recapitato all'app.

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

Risorse