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
- Introduzione a WinUI
- Creare un nuovo progetto che usa Windows App SDK OPPURE usare Windows App SDK in un progetto esistente
- Per usare le notifiche push di Windows App SDK, è necessario un Account Azure.
- Leggere Panoramica delle notifiche push
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
Immetti un nome per l'app.
Le notifiche push richiedono l'opzione multi-tenant, quindi selezionare questa opzione.
- Per altre informazioni sui tenant, vedere Chi può accedere all'app?
Selezionare Registra
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.
Prendere nota dell'ID Directory (tenant), poiché si tratta di Azure TenantId che verrà usato quando si richiede un token di accesso.
Importante
Prendere nota dell'ID Applicazione (client) e dell'ID Directory (tenant).
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:
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 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.
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
Se l'app è inclusa in un pacchetto con una posizione esterna, puoi 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 in pacchetto, creare una richiesta di mapping PFN (Package Family Name) inviando un messaggio di Win_App_SDK_Push@microsoft.com posta elettronica con la riga dell'oggetto "SDK per app di Windows Push Notifications Mapping Request" e il corpo "PFN: [your PFN]", AppId: [your APPId], ObjectId: [your ObjectId]. Le richieste di mapping 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 Id
valori , Executable
e 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:
- Registrare l'app per ricevere notifiche push richiedendo PushNotificationManager::D efault(). Register().
- 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);