Inicio rápido: Notificaciones push en el SDK de Aplicaciones para Windows

En este artículo de inicio rápido creará una aplicación de Windows de escritorio que envía y recibe notificaciones push mediante el SDK de Aplicaciones para Windows.

Requisitos previos

Aplicación de ejemplo

En este artículo de inicio rápido se explica cómo agregar compatibilidad con notificaciones push a la aplicación. Consulte el código de ejemplo de este artículo de inicio rápido en contexto en las aplicaciones de ejemplo que se encuentran en GitHub.

Referencia de la API

Para obtener documentación de referencia de la API para las notificaciones push, consulte Espacio de nombres Microsoft.Windows.AppNotifications.

Configuración de la identidad de la aplicación en Azure Active Directory (AAD)

Las notificaciones push en el SDK de Aplicaciones para Windows utilizan identidades de Azure Active Directory (AAD). Las credenciales de Azure son obligatorias al solicitar un URI del canal WNS y al solicitar tokens de acceso para enviar notificaciones push. Nota: NO se admite el uso de notificaciones push del SDK de Aplicaciones para Windows con el Centro de partners de Microsoft.

Paso 1: Crear un registro de aplicación de AAD

Inicie sesión en su cuenta de Azure y cree un nuevo recurso de Registro de aplicación de AAD. Seleccione Nuevo registro.

Paso 2: Proporcionar un nombre y seleccionar una opción multiinquilino

  1. Especifique un nombre de la aplicación.

  2. Las notificaciones push requieren la opción multiinquilino, así que selecciónela.

    1. Para obtener más información sobre los inquilinos, consulte ¿Quién puede iniciar sesión en su aplicación?
  3. Seleccione Registrar.

  4. Anote el Id. de aplicación (cliente), ya que esta es el Azure AppId que usará durante el registro de activación y la solicitud del token de acceso.

  5. Anote el Id. de directorio (inquilino), ya que este es el Azure TenantId que utilizará al solicitar un token de acceso.

    Importante

    AAD App Registration Tenant Anote el Id. de aplicación (cliente) y el Id. de directorio (inquilino).

  6. Anote el Id. de objeto, ya que este es el Azure ObjectId que utilizará al solicitar una solicitud de canal. Tenga en cuenta que no es el identificador de objeto que aparece en la página Información esencial. En su lugar, para buscar el Id. de objeto correcto, haga clic en el nombre de la aplicación en el campo Aplicación administrada en el directorio local de la página Información esencial:

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

    Screenshot showing the Object ID field

    Nota:

    Se requiere una entidad de servicio para obtener un Id. de objeto. Si no hay uno asociado a la aplicación, siga los pasos descritos en uno de los artículos a continuación para crear uno en Azure Portal o mediante la línea de comandos:

    Uso del portal para crear una aplicación de Azure AD y una entidad de servicio con acceso a los recursos

    Uso de Azure PowerShell para crear una entidad de servicio con un certificado

Paso 3: Crear un secreto para el registro de aplicación

El secreto se utilizará junto con el Azure AppId/ClientId al solicitar un token de acceso para enviar notificaciones push.

AAD App Secret

Vaya a Certificados y secretos y seleccione Nuevo secretos de cliente.

Importante

Después de crear el secreto, asegúrese de copiarlo y almacenarlo en una ubicación segura, como Azure Key Vault. Solo se podrá ver una vez después de la creación.

Paso 4: Asignar el nombre de familia de paquete de la aplicación a su Azure AppId

Importante

Los Servicios de notificaciones de inserción de Windows (WNS) ahora están integrado en Azure Portal. La nueva experiencia de registro está disponible en versión preliminar. Si se trata de una aplicación empaquetada (incluidas las empaquetadas con ubicación externa), puede seguir este flujo para asignar el nombre de familia de paquete (PFN) de la aplicación y su Azure AppId.

Si la aplicación es una aplicación Win32 empaquetada, solicite acceso a nuestra nueva experiencia de versión preliminar de Azure Portal mediante el correo electrónico Win_App_SDK_Push@microsoft.com con la línea de asunto "Windows App SDK Push Notifications Request" y el cuerpo "Azure Subscription: [su identificador de suscripción de Azure]". Se cumple con las solicitudes cada semana. Recibirá una notificación una vez completada la solicitud de asignación.

Configurar la aplicación para recibir notificaciones push

Paso 1: Agregar declaraciones de espacios de nombres

Agregue el espacio de nombres para las notificaciones push del SDK de Aplicaciones para Windows Microsoft.Windows.PushNotifications.

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

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

Paso 2: Agregar el activador COM al manifiesto de la aplicación

Importante

Si la aplicación está desempaquetada (es decir, carece de identidad de paquete en tiempo de ejecución), vaya al Paso 3: Registrarse y responder a notificaciones push al iniciar la aplicación.

Si la aplicación está empaquetada (incluidas aplicaciones empaquetadas con ubicación externa), abra Package.appxmanifest. Agregue lo siguiente dentro del elemento <Application>. Reemplace los valores Id, Executable y DisplayName por los específicos de la aplicación.

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

Paso 3: Registrar y responder a notificaciones push al iniciar la aplicación

Actualice el método main() de la aplicación para agregar lo siguiente:

  1. Llame a PushNotificationManager::Default().Register() para registrar la aplicación para recibir notificaciones push.
  2. Llame a AppInstance::GetCurrent().GetActivatedEventArgs() para comprobar el origen de la solicitud de activación. Si la activación se desencadenó desde una notificación push, responda en función de la carga de la notificación.

Importante

Debe llamar a PushNotificationManager::Default().Register antes de llamar a AppInstance.GetCurrent.GetActivatedEventArgs.

El ejemplo siguiente procede de la aplicación empaquetada de ejemplo que se encuentra en 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.
}

Paso 4: Solicitar un URI del canal WNS y registrarlo en el servidor WNS

Los URI del canal WNS son los puntos de conexión HTTP para enviar notificaciones push. Cada cliente debe solicitar un URI de canal y registrarlo en el servidor WNS para recibir notificaciones push.

Nota:

Los URI del canal WNS expiran después de 30 días.

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

PushNotificationManager intentará crear un URI de canal, y lo reintentará automáticamente durante un máximo de 15 minutos. Cree un controlador de eventos para esperar a que se complete la llamada. Una vez completada la llamada, si se completó correctamente, registre el URI en el servidor 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;
}

Paso 5: Compilar e instalar la aplicación

Utilice Visual Studio para compilar e instalar la aplicación. Haga clic con el botón derecho en el archivo de la solución en el Explorador de soluciones y seleccione Implementar. Visual Studio compilará la aplicación y la instalará en la máquina. Para ejecutar la aplicación, puede iniciarla mediante el menú Inicio o el depurador de Visual Studio.

Enviar una notificación push a la aplicación

En este momento, se completa toda la configuración y el servidor WNS puede enviar notificaciones push a las aplicaciones cliente. En los pasos siguientes, consulte los encabezados de solicitud y respuesta del servidor de notificaciones push para obtener más detalles.

Paso 1: Solicitar un token de acceso

Para enviar una notificación push, el servidor WNS primero debe solicitar un token de acceso. Envíe una solicitud HTTP POST con el Azure TenantId, Azure AppId y el secreto. Para obtener información sobre cómo recuperar el Azure TenantId y Azure AppId, consulte Obtener valores de identificador de inquilino y aplicación para iniciar sesión.

Solicitud HTTP de ejemplo:

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/

Solicitud C# de ejemplo:

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

Si la solicitud se completa correctamente, recibirá una respuesta que contiene el token en el campo access_token.

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

Paso 2. Envío de una notificación sin procesar

Cree una solicitud HTTP POST que contenga el token de acceso que obtuvo en el paso anterior y el contenido de la notificación push que desea enviar. El contenido de la notificación push se entregará a la aplicación.

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

Paso 3: Enviar una notificación de aplicación con origen en la nube

Si solo le interesa enviar notificaciones sin procesar, omita este paso. Para enviar una notificación de aplicación con origen en la nube, también conocida como notificación push del sistema, primero siga el artículo Inicio rápido: Notificaciones de aplicación en el SDK de Aplicaciones para Windows. Las notificaciones de aplicación pueden ser push (enviadas desde la nube) o enviarse localmente. El envío de una notificación de aplicación con origen en la nube es similar al envío de una notificación sin procesar del Paso 2, excepto que el encabezado X-WNS-Type es toast, Content-Type es text/xml y el contenido incluye la carga útil XML de la notificación de aplicación. Consulte Esquema XML de notificaciones para obtener más información sobre cómo construir la carga XML.

Cree una solicitud HTTP POST que contenga el token de acceso y el contenido de la notificación de aplicación con origen en la nube que desea enviar. El contenido de la notificación push se entregará a la aplicación.

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

Recursos