Tutorial: Envío de notificaciones push a aplicaciones de Xamarin.Forms mediante Azure Notification Hubs mediante un servicio back-end

Descargar ejemplo Descargar el de ejemplo

En este tutorial, usará de Azure Notification Hubs para enviar notificaciones push a una aplicación de Xamarin.Forms dirigida a android y de iOS.

Se usa un back-end api web de ASP.NET Core para controlar de registro de dispositivos para el cliente mediante el enfoque de instalación de más reciente y mejor . El servicio también enviará notificaciones push de forma multiplataforma.

Estas operaciones se controlan mediante el SDK de Notification Hubs para operaciones de back-end. Se proporciona más información sobre el enfoque general en la documentación de Registro desde el back-end de la aplicación.

Este tutorial le guía por los pasos siguientes:

Prerrequisitos

Para continuar, necesita lo siguiente:

Para Android, debe tener:

  • Un dispositivo físico desbloqueado por el desarrollador o un emulador (ejecutando la API 26 y versiones posteriores con Google Play Services instalado).

Para iOS, debe tener:

  • Una cuenta de desarrollador de Apple activa .
  • Un dispositivo iOS físico que se registrado en la cuenta de desarrollador(ejecutando iOS 13.0 y versiones posteriores).
  • Un certificado de desarrollo de .p12instalado en la cadena de claves le permite ejecutar una aplicación en un dispositivo físico.

Nota

El simulador de iOS no admite notificaciones remotas y, por tanto, se requiere un dispositivo físico al explorar este ejemplo en iOS. Sin embargo, no es necesario ejecutar la aplicación en android y iOS para completar este tutorial.

Puede seguir los pasos descritos en este ejemplo de primeros principios sin experiencia previa. Sin embargo, se beneficiará de tener conocimientos sobre los siguientes aspectos.

Importante

Los pasos proporcionados son específicos de Visual Studio para Mac. Es posible seguir el uso de visual Studio 2019, pero puede haber algunas diferencias para conciliar. Por ejemplo, descripciones de la interfaz de usuario y los flujos de trabajo, nombres de plantilla, configuración del entorno, etc.

Configuración de Servicios de notificaciones push y Centro de notificaciones de Azure

En esta sección, configurará firebase Cloud Messaging (FCM) y Apple Push Notification Services (APNS). A continuación, cree y configure un centro de notificaciones para trabajar con esos servicios.

Creación de un proyecto de Firebase y habilitación de Firebase Cloud Messaging para Android

  1. Inicie sesión en la consola de Firebase. Cree un nuevo proyecto de Firebase que escriba PushDemo como nombre del proyecto de .

    Nota

    Se generará un nombre único automáticamente. De forma predeterminada, se compone de una variante minúscula del nombre que proporcionó más un número generado separado por un guión. Puede cambiar esto si quiere proporcionarlo todavía es único globalmente.

  2. Después de crear el proyecto, seleccione Agregar Firebase a la aplicación Android.

    Agregar Firebase a la aplicación Android

  3. En la página Agregar Firebase a la aplicación Android, siga estos pasos.

    1. En el nombre del paquete de Android, escriba un nombre para el paquete. Por ejemplo: com.<organization_identifier>.<package_name>.

      Especificar el nombre del paquete

    2. Seleccione Registrar aplicación.

    3. Seleccione Descargar google-services.json. A continuación, guarde el archivo en una carpeta local para usarlo más adelante y seleccione Siguiente.

      descargar google-services.json

    4. Seleccione Siguiente.

    5. Seleccione continuar con la consola

      Nota

      Si la botón Continuar con la consola no está habilitada, debido a la comprobación del de instalación de , elija Omitir este paso.

  4. En la consola de Firebase, seleccione el engranaje del proyecto. A continuación, seleccione Configuración del proyecto.

    seleccionar la configuración del proyecto

    Nota

    Si no ha descargado el archivo google-services.json, puede descargarlo en esta página.

  5. Cambie a la pestaña Cloud Messaging en la parte superior. Copie y guarde la clave de Server para su uso posterior. Use este valor para configurar el centro de notificaciones.

    copia de la clave del servidor

Registro de la aplicación iOS para notificaciones push

Para enviar notificaciones push a una aplicación iOS, registre la aplicación con Apple y también regístrese para recibir notificaciones push.

  1. Si aún no ha registrado la aplicación, vaya al portal de aprovisionamiento de iOS en el Centro para desarrolladores de Apple. Inicie sesión en el portal con el identificador de Apple, vaya a certificados , identificadores & perfilesy, a continuación, seleccione Identificadores. Haga clic en + para registrar una nueva aplicación.

    página de identificadores de aplicación del portal de aprovisionamiento de iOS

  2. En la pantalla Registrar un nuevo identificador, seleccione el botón de radio Identificadores de aplicación. A continuación, seleccione Continuar.

    portal de aprovisionamiento de iOS, registre una nueva página de identificador

  3. Actualice los tres valores siguientes para la nueva aplicación y seleccione Continuar:

    • Descripción: escriba un nombre descriptivo para la aplicación.

    • id. de lote: escriba un identificador de lote del formulario com.<organization_identifier>.<product_name> tal como se mencionó en la Guía de distribución de aplicaciones de . En la captura de pantalla siguiente, el valor de mobcat se usa como identificador de organización y el valor PushDemo se usa como nombre del producto.

      página de id. de aplicación de registro del portal de aprovisionamiento de iOS

    • Notificaciones push: active la opción Notificaciones push de en la sección Funcionalidades de .

      Formulario para registrar un nuevo identificador de aplicación

      Esta acción genera el identificador de la aplicación y las solicitudes que confirma la información. Seleccione Continue(Continuar) y, a continuación, seleccione Register (Registrar) para confirmar el nuevo identificador de aplicación.

      Confirmar nuevo identificador de aplicación

      Después de seleccionar Registrar, verá el nuevo identificador de aplicación como un elemento de línea en la página certificados, identificadores & perfiles de .

  4. En la página certificados de , identificadores & perfiles, en Identificadores, busque el elemento de línea Id. de aplicación que creó. A continuación, seleccione su fila para mostrar la pantalla Editar la configuración del identificador de aplicación.

Creación de un certificado para Notification Hubs

Se requiere un certificado para permitir que el centro de notificaciones funcione con apple Push Notification Services (APNS) y se puede proporcionar de una de estas dos maneras:

  1. Creación de un certificado de inserción p12 que se puede cargar directamente en notification Hub (el enfoque original)

  2. Creación de un certificado p8 que se puede usar para la autenticación basada en tokens (el enfoque más reciente y recomendado)

El enfoque más reciente tiene varias ventajas, tal y como se documenta en la autenticación basada en tokens (HTTP/2) para APNS. Se requieren menos pasos, pero también se exige para escenarios específicos. Sin embargo, se han proporcionado pasos para ambos enfoques, ya que cualquiera de los dos funcionará para los fines de este tutorial.

OPCIÓN 1: Creación de un certificado de inserción p12 que se puede cargar directamente en el Centro de notificaciones
  1. En el equipo Mac, ejecute la herramienta Acceso a llaveros. Se puede abrir desde la carpeta Utilidades o la carpeta Otros del Launchpad.

  2. Seleccione acceso a llaveros, expanda asistente para certificados y, a continuación, seleccione Solicitar un certificado de una entidad de certificación.

    Usar acceso a llaves para solicitar un nuevo certificado

    Nota

    De forma predeterminada, Keychain Access selecciona el primer elemento de la lista. Esto puede ser un problema si está en la categoría certificados y entidad de certificación de relaciones para desarrolladores de Apple Worldwide no es el primer elemento de la lista. Asegúrese de que tiene un elemento que no es clave o de que está seleccionada la entidad de certificación de relaciones para desarrolladores de Apple Worldwide clave, antes de generar la CSR (solicitud de firma de certificado).

  3. Seleccione eldirección de correo electrónico de usuario de , escriba el valor Nombre común , asegúrese de especificar Guardado en discoy, a continuación, seleccione Continuar. Deje dirección de correo electrónico de CA en blanco, ya que no es necesario.

    información de certificado esperada

  4. Escriba un nombre para el archivo solicitud de firma de certificado (CSR) en Guardar como, seleccione la ubicación en Wherey, a continuación, seleccione Guardar.

    Elegir un nombre de archivo para el certificado

    Esta acción guarda el archivo CSR de en la ubicación seleccionada. La ubicación predeterminada es Desktop. Recuerde la ubicación elegida para el archivo.

  5. De nuevo en la página certificados de , identificadores & perfiles del portal de aprovisionamiento de iOS , desplácese hacia abajo hasta la opción Notificaciones push activadas y, a continuación, seleccione Configurar para crear el certificado.

    página Editar id. de aplicación

  6. Aparece la ventana de certificados TLS/SSL del servicio de notificaciones push de Apple. Seleccione el botón Create Certificate (Crear certificado) en la sección De certificados TLS/SSL de desarrollo de .

    botón Crear certificado para el identificador de aplicación

    Se muestra la pantalla Crear un nuevo certificado.

    Nota

    En este tutorial se usa un certificado de desarrollo. El mismo proceso se usa al registrar un certificado de producción. Solo tiene que asegurarse de usar el mismo tipo de certificado al enviar notificaciones.

  7. Seleccione Elija archivo, vaya a la ubicación donde guardó el archivo CSR de y haga doble clic en el nombre del certificado para cargarlo. A continuación, seleccione Continuar.

  8. Después de crear el certificado en el portal, seleccione el botón Descargar . Guarde el certificado y recuerde la ubicación en la que se guarda.

    página de descarga de certificados generados

    El certificado se descarga y guarda en el equipo en la carpeta descargas de .

    Buscar archivo de certificado en la carpeta Descargas

    Nota

    De forma predeterminada, el certificado de desarrollo descargado se denomina aps_development.cer.

  9. Haga doble clic en el certificado de inserción descargado aps_development.cer. Esta acción instala el nuevo certificado en la cadena de claves, como se muestra en la imagen siguiente:

    lista de certificados de acceso a llaves en la que se muestran nuevos certificados

    Nota

    Aunque el nombre del certificado puede ser diferente, el nombre tendrá el prefijo Apple Development iOS Push Services y tendrá asociado el identificador de lote adecuado.

  10. En Acceso a llaveros, ControlHaga clic en el nuevo certificado de inserción que creó en la categoría certificados de . Seleccione Exportar, asigne un nombre al archivo, seleccione el formato de p12 y, a continuación, seleccione Guardar.

    Exportar certificado con formato p12

    Puede optar por proteger el certificado con una contraseña, pero una contraseña es opcional. Haga clic en Aceptar si desea omitir la creación de contraseñas. Anote el nombre de archivo y la ubicación del certificado p12 exportado. Se usan para habilitar la autenticación con APN.

    Nota

    El nombre y la ubicación del archivo p12 pueden ser diferentes de lo que se muestra en este tutorial.

OPCIÓN 2: Creación de un certificado p8 que se puede usar para la autenticación basada en tokens
  1. Anote los detalles siguientes:

    • de prefijo de id. de aplicación (id. de equipo)
    • de identificador de lote
  2. De nuevo en certificados de , identificadores & perfiles, haga clic en Claves.

    Nota

    Si ya tiene una clave configurada para APNS, puede volver a usar el certificado p8 que descargó justo después de crearlo. Si es así, puede omitir los pasos 3 a través de 5.

  3. Haga clic en el botón + (o botón Crear una clave) para crear una nueva clave.

  4. Proporcione un nombre de clave adecuado y, a continuación, active la opción servicio de notificaciones push de Apple (APNS) y, a continuación, haga clic en Continuar, seguido de Registrar en la siguiente pantalla.

  5. Haga clic en Descargar y, a continuación, mueva el archivo p8 de (con el prefijo AuthKey_) a un directorio local seguro y, a continuación, haga clic en Listo.

    Nota

    Asegúrese de mantener el archivo p8 en un lugar seguro (y guardar una copia de seguridad). Después de descargar la clave, no se puede volver a descargar a medida que se quita la copia del servidor.

  6. En claves, haga clic en la clave que creó (o una clave existente si ha elegido usarla en su lugar).

  7. Anote el valor id. de clave de .

  8. Abra el certificado p8 en una aplicación adecuada de su elección, como Visual Studio Code. Anote el valor de clave (entre -----BEGIN PRIVATE KEY----- y -----END PRIVATE KEY-----).

    -----BEGIN PRIVATE KEY-----
    <key_value>
    -----END PRIVATE KEY-----

    Nota

    Este es el valor de token de que se usará más adelante para configurar Notification Hub.

Al final de estos pasos, debe tener la siguiente información para usarla más adelante en Configuración del centro de notificaciones con información de APNS:

  • de id. de equipo (consulte el paso 1)
  • de identificador de lote (consulte el paso 1)
  • id. de clave (consulte el paso 7)
  • valor de token (valor de clave p8 obtenido en el paso 8)

Creación de un perfil de aprovisionamiento para la aplicación

  1. Vuelva al portal de aprovisionamiento de iOS , seleccione Certificados, Identificadores & Perfiles, seleccione Perfiles en el menú de la izquierda y, a continuación, seleccione + para crear un nuevo perfil. Aparece la pantalla Registrar un nuevo perfil de aprovisionamiento.

  2. Seleccione desarrollo de aplicaciones de iOS en Development como tipo de perfil de aprovisionamiento y, a continuación, seleccione Continuar.

    lista de perfiles de aprovisionamiento

  3. A continuación, seleccione el identificador de aplicación que creó en la lista desplegable Id. de aplicación y seleccione Continuar.

    Seleccionar el identificador de aplicación

  4. En la ventana Seleccionar certificados, seleccione el certificado de desarrollo que usa para la firma de código y seleccione Continuar.

    Nota

    Este certificado no es el certificado de inserción que creó en el paso anterior . Este es el certificado de desarrollo. Si no existe, debe crearlo, ya que se trata de un requisito previo para este tutorial. Los certificados de desarrollador se pueden crear enportal para desarrolladores de Apple mediante Xcode o en Visual Studio.

  5. Vuelva a la página Certificados , Identificadores & Perfiles, seleccione Perfiles en el menú de la izquierda y, a continuación, seleccione + para crear un nuevo perfil. Aparece la pantalla Registrar un nuevo perfil de aprovisionamiento.

  6. En la ventana seleccionar certificados , seleccione el certificado de desarrollo que creó. A continuación, seleccione Continuar.

  7. A continuación, seleccione los dispositivos que se van a usar para realizar pruebas y seleccione Continuar.

  8. Por último, elija un nombre para el perfil en Nombre del perfil de aprovisionamientoy seleccione Generar.

    Elegir un nombre de perfil de aprovisionamiento

  9. Cuando se crea el nuevo perfil de aprovisionamiento, seleccione Descargar. Recuerde la ubicación a la que se guarda.

  10. Vaya a la ubicación del perfil de aprovisionamiento y haga doble clic en él para instalarlo en la máquina de desarrollo.

Creación de un centro de notificaciones

En esta sección, creará un centro de notificaciones y configurará la autenticación con APNS. Puede usar un certificado de inserción p12 o una autenticación basada en tokens. Si desea usar un centro de notificaciones que ya ha creado, puede ir directamente al paso 5.

  1. Inicie sesión en Azure.

  2. Haga clic en Crear un recursoy, después, busque y elija centro de notificaciones y haga clic en Crear.

  3. Actualice los campos siguientes y, a continuación, haga clic en Crear:

    DETALLES BÁSICOS

    Suscripción: Elija la suscripción de destino en la lista desplegable.
    grupo de recursos: Crear un nuevo grupo de recursos (o elegir uno existente)

    DETALLES DEL ESPACIO DE NOMBRES

    Namespace del Centro de notificaciones: Escriba un nombre único global para el espacio de nombres del centro de notificaciones de

    Nota

    Asegúrese de que la opción Crear nueva esté seleccionada para este campo.

    NOTIFICATION HUB DETAILS

    Centro de notificaciones: Escriba un nombre para el centro de notificaciones de
    Ubicación: Elegir una ubicación adecuada en la lista desplegable
    plan de tarifa: mantener la opción predeterminada gratis

    Nota

    A menos que haya alcanzado el número máximo de concentradores en el nivel gratis.

  4. Una vez que se ha aprovisionado el del centro de notificaciones de , vaya a ese recurso.

  5. Vaya al nuevo centro de notificaciones de .

  6. Seleccione directivas de acceso en la lista (en ADMINISTRAR).

  7. Anote los valores nombre de directiva de junto con sus valores de cadena de conexión correspondientes .

Configuración del Centro de notificaciones con información de APNS

En Notification Services, seleccione Apple, a continuación, siga los pasos adecuados según el enfoque que eligió anteriormente en la sección Creación de un certificado para Notification Hubs.

Nota

Usa el de producción de para modo de aplicación solo si quieres enviar notificaciones push a los usuarios que compraron la aplicación desde la tienda.

OPCIÓN 1: Uso de un certificado de inserción .p12

  1. Seleccione certificado.

  2. Seleccione el icono de archivo.

  3. Seleccione el archivo .p12 que exportó anteriormente y, a continuación, seleccione Abrir.

  4. Si es necesario, especifique la contraseña correcta.

  5. Seleccione modo de espacio aislado.

  6. Seleccione Guardar.

OPCIÓN 2: Uso de la autenticación basada en tokens

  1. Seleccione token.

  2. Escriba los valores siguientes que adquirió anteriormente:

    • de identificador de clave de
    • de identificador de lote
    • id. de equipo de
    • de token de
  3. Elija espacio aislado.

  4. Seleccione Guardar.

Configuración del centro de notificaciones con información de FCM

  1. Seleccione Google (GCM/FCM) en la sección configuración de del menú izquierdo.
  2. Escriba la clave del servidor anotó en la Google Firebase Console.
  3. Seleccione Guardar en la barra de herramientas.

Creación de una aplicación back-end de API web de ASP.NET Core

En esta sección, creará el back-end de ASP.NET Core Web API para controlar de registro de dispositivos y el envío de notificaciones a la aplicación móvil de Xamarin.Forms.

Creación de un proyecto web

  1. En visual Studio, seleccione Archivo>Nueva solución.

  2. Seleccione .NET Core>App>ASP.NET Core>API>Siguiente.

  3. En el cuadro de diálogo Configure your new ASP.NET Core Web API ,seleccione Target Framework de .NET Core 3.1.

  4. Escriba PushDemoApi para el Nombre del proyecto de y, a continuación, seleccione Crear.

  5. Inicie la depuración (Comando + Escriba) para probar la aplicación con plantilla.

    Nota

    La aplicación con plantilla está configurada para usar el WeatherForecastController como launchUrl . Esto se establece en Propiedades>launchSettings.json.

    Si se le solicita un certificado de desarrollo no válido encontrado mensaje:

    1. Haga clic en para aceptar ejecutar la herramienta "dotnet dev-certs https" para corregirlo. La herramienta "dotnet dev-certs https" le pedirá que escriba una contraseña para el certificado y la contraseña de la cadena de claves.

    2. Haga clic en cuando se le pida que Instalar y confíe en el nuevo certificadoy escriba la contraseña de la cadena de claves.

  6. Expanda la carpeta Controladores de y elimine WeatherForecastController.cs.

  7. Elimine WeatherForecast.cs.

  8. Configure los valores de configuración local mediante la herramienta administrador de secretos de . Desacoplar los secretos de la solución garantiza que no terminan en el control de código fuente. Abra Terminal vaya al directorio del archivo del proyecto y ejecute los comandos siguientes:

    dotnet user-secrets init
    dotnet user-secrets set "NotificationHub:Name" <value>
    dotnet user-secrets set "NotificationHub:ConnectionString" <value>
    

    Reemplace los valores de marcador de posición por su propio nombre del centro de notificaciones y los valores de cadena de conexión. Los anotó en la sección crear un centro de notificaciones. De lo contrario, puede buscarlos en Azure.

    NotificationHub:Name:
    Consulte Name (Nombre) en el resumen de de Essentials en la parte superior de Información general.

    NotificationHub:ConnectionString:
    Consulte DefaultFullSharedAccessSignature en directivas de acceso

    Nota

    En escenarios de producción, puede ver opciones como Azure KeyVault para almacenar de forma segura la cadena de conexión. Por motivos de simplicidad, los secretos se agregarán a la configuración de la aplicación de Azure App Service .

Autenticación de clientes mediante una clave de API (opcional)

Las claves de API no son tan seguras como tokens, pero bastarán con los fines de este tutorial. Una clave de API se puede configurar fácilmente a través del middleware ASP.NET.

  1. Agregue la clave de API de a los valores de configuración local.

    dotnet user-secrets set "Authentication:ApiKey" <value>
    

    Nota

    Debe reemplazar el valor del marcador de posición por el suyo propio y anotarlo.

  2. Control + Haga clic en el proyecto PushDemoApi, elija Nueva carpeta en el menú Agregar y, a continuación, haga clic en Agregar mediante Autenticación como nombre de carpeta .

  3. ControlHaga clic en en la carpeta autenticación de y elija Nuevo archivo... en el menú Agregar .

  4. Seleccione GeneralClase vacía, escriba ApiKeyAuthOptions.cs para elNombre de y haga clic en Nuevo agregar la siguiente implementación.

    using Microsoft.AspNetCore.Authentication;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthOptions : AuthenticationSchemeOptions
        {
            public const string DefaultScheme = "ApiKey";
            public string Scheme => DefaultScheme;
            public string ApiKey { get; set; }
        }
    }
    
  5. Agregue otra clase vacía a la carpeta Authentication denominada ApiKeyAuthHandler.csy agregue la siguiente implementación.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using System.Text.Encodings.Web;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    
    namespace PushDemoApi.Authentication
    {
        public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions>
        {
            const string ApiKeyIdentifier = "apikey";
    
            public ApiKeyAuthHandler(
                IOptionsMonitor<ApiKeyAuthOptions> options,
                ILoggerFactory logger,
                UrlEncoder encoder,
                ISystemClock clock)
                : base(options, logger, encoder, clock) {}
    
            protected override Task<AuthenticateResult> HandleAuthenticateAsync()
            {
                string key = string.Empty;
    
                if (Request.Headers[ApiKeyIdentifier].Any())
                {
                    key = Request.Headers[ApiKeyIdentifier].FirstOrDefault();
                }
                else if (Request.Query.ContainsKey(ApiKeyIdentifier))
                {
                    if (Request.Query.TryGetValue(ApiKeyIdentifier, out var queryKey))
                        key = queryKey;
                }
    
                if (string.IsNullOrWhiteSpace(key))
                    return Task.FromResult(AuthenticateResult.Fail("No api key provided"));
    
                if (!string.Equals(key, Options.ApiKey, StringComparison.Ordinal))
                    return Task.FromResult(AuthenticateResult.Fail("Invalid api key."));
    
                var identities = new List<ClaimsIdentity> {
                    new ClaimsIdentity("ApiKeyIdentity")
                };
    
                var ticket = new AuthenticationTicket(
                    new ClaimsPrincipal(identities), Options.Scheme);
    
                return Task.FromResult(AuthenticateResult.Success(ticket));
            }
        }
    }
    

    Nota

    Un controlador de autenticación es un tipo que implementa el comportamiento de un esquema, en este caso un esquema de clave de API personalizado.

  6. Agregue otra de clase vacía a la carpeta autenticación de denominada ApiKeyAuthenticationBuilderExtensions.csy agregue la siguiente implementación.

    using System;
    using Microsoft.AspNetCore.Authentication;
    
    namespace PushDemoApi.Authentication
    {
        public static class AuthenticationBuilderExtensions
        {
            public static AuthenticationBuilder AddApiKeyAuth(
                this AuthenticationBuilder builder,
                Action<ApiKeyAuthOptions> configureOptions)
            {
                return builder
                    .AddScheme<ApiKeyAuthOptions, ApiKeyAuthHandler>(
                        ApiKeyAuthOptions.DefaultScheme,
                        configureOptions);
            }
        }
    }
    

    Nota

    Este método de extensión simplifica el código de configuración de middleware en Startup.cs lo que hace que sea más legible y, por lo general, más fácil de seguir.

  7. En Startup.cs, actualice el método ConfigureServices para configurar la autenticación de clave de API debajo de la llamada a los servicios de . AddControllers método.

    using PushDemoApi.Authentication;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    
        services.AddAuthentication(options =>
        {
            options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme;
            options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme;
        }).AddApiKeyAuth(Configuration.GetSection("Authentication").Bind);
    }
    
  8. Todavía en Startup.cs, actualice el método Configure para llamar al UseAuthentication y métodos de extensión UseAuthorization en la IApplicationBuilder de la aplicación. Asegúrese de que se llama a esos métodos después de useRouting y antes de aplicación. UseEndpoints.

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        app.UseHttpsRedirection();
    
        app.UseRouting();
    
        app.UseAuthentication();
    
        app.UseAuthorization();
    
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
    

    Nota

    Al llamar a UseAuthentication se registra el middleware que usa los esquemas de autenticación registrados anteriormente (de ConfigureServices). Se debe llamar a esto antes de cualquier middleware que dependa de los usuarios que se autentiquen.

Adición de dependencias y configuración de servicios

ASP.NET Core admite el patrón de diseño de software inserción de dependencias (DI), que es una técnica para lograr inversión de control (IoC) entre clases y sus dependencias.

El uso del centro de notificaciones y el SDK de Notification Hubs para operaciones de back-end se encapsula dentro de un servicio. El servicio se registra y está disponible a través de una abstracción adecuada.

  1. ControlHaga clic en en la carpeta Dependencias de y elija Administrar paquetes NuGet....

  2. Busque Microsoft.Azure.NotificationHubs y asegúrese de que está activada.

  3. Haga clic en Agregar paquetesy, a continuación, haga clic en Aceptar cuando se le pida que acepte los términos de licencia.

  4. ControlHaga clic en en el proyecto PushDemoApi, elija Nueva carpeta en el menú Agregar y, a continuación, haga clic en Agregar mediante Models como nombre de carpeta .

  5. ControlHaga clic en en la carpeta modelos de y elija Nuevo archivo... en el menú Agregar .

  6. Seleccione clase vacía, escriba PushTemplates.cs para elNombre de y, a continuación, haga clic en Nuevo agregar la siguiente implementación.

    namespace PushDemoApi.Models
    {
        public class PushTemplates
        {
            public class Generic
            {
                public const string Android = "{ \"notification\": { \"title\" : \"PushDemo\", \"body\" : \"$(alertMessage)\"}, \"data\" : { \"action\" : \"$(alertAction)\" } }";
                public const string iOS = "{ \"aps\" : {\"alert\" : \"$(alertMessage)\"}, \"action\" : \"$(alertAction)\" }";
            }
    
            public class Silent
            {
                public const string Android = "{ \"data\" : {\"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\"} }";
                public const string iOS = "{ \"aps\" : {\"content-available\" : 1, \"apns-priority\": 5, \"sound\" : \"\", \"badge\" : 0}, \"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\" }";
            }
        }
    }
    

    Nota

    Esta clase contiene las cargas de notificación con token para las notificaciones genéricas y silenciosas requeridas por este escenario. Las cargas se definen fuera del instalación de para permitir la experimentación sin tener que actualizar las instalaciones existentes a través del servicio. El control de los cambios en las instalaciones de esta manera está fuera del ámbito de este tutorial. Para producción, considere plantillas personalizadas.

  7. Agregue otra clase vacía a la carpeta Models denominada DeviceInstallation.csy agregue la siguiente implementación.

    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class DeviceInstallation
        {
            [Required]
            public string InstallationId { get; set; }
    
            [Required]
            public string Platform { get; set; }
    
            [Required]
            public string PushChannel { get; set; }
    
            public IList<string> Tags { get; set; } = Array.Empty<string>();
        }
    }
    
  8. Agregue otra clase vacía a la carpeta Models denominada NotificationRequest.csy agregue la siguiente implementación.

    using System;
    
    namespace PushDemoApi.Models
    {
        public class NotificationRequest
        {
            public string Text { get; set; }
            public string Action { get; set; }
            public string[] Tags { get; set; } = Array.Empty<string>();
            public bool Silent { get; set; }
        }
    }
    
  9. Agregue otra clase vacía a la carpeta Models denominada NotificationHubOptions.csy agregue la siguiente implementación.

    using System.ComponentModel.DataAnnotations;
    
    namespace PushDemoApi.Models
    {
        public class NotificationHubOptions
        {
            [Required]
            public string Name { get; set; }
    
            [Required]
            public string ConnectionString { get; set; }
        }
    }
    
  10. Agregue una nueva carpeta al proyecto de PushDemoApi denominado Services.

  11. Agregue una interfaz vacía a la carpeta Services denominada INotificationService.csy agregue la siguiente implementación.

    using System.Threading;
    using System.Threading.Tasks;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.Services
    {
        public interface INotificationService
        {
            Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token);
            Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token);
            Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token);
        }
    }
    
  12. Agregue una clase vacía a la carpeta de Services denominada NotificationHubsService.csy agregue el código siguiente para implementar la interfaz de INotificationService:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Options;
    using PushDemoApi.Models;
    
    namespace PushDemoApi.Services
    {
        public class NotificationHubService : INotificationService
        {
            readonly NotificationHubClient _hub;
            readonly Dictionary<string, NotificationPlatform> _installationPlatform;
            readonly ILogger<NotificationHubService> _logger;
    
            public NotificationHubService(IOptions<NotificationHubOptions> options, ILogger<NotificationHubService> logger)
            {
                _logger = logger;
                _hub = NotificationHubClient.CreateClientFromConnectionString(
                    options.Value.ConnectionString,
                    options.Value.Name);
    
                _installationPlatform = new Dictionary<string, NotificationPlatform>
                {
                    { nameof(NotificationPlatform.Apns).ToLower(), NotificationPlatform.Apns },
                    { nameof(NotificationPlatform.Fcm).ToLower(), NotificationPlatform.Fcm }
                };
            }
    
            public async Task<bool> CreateOrUpdateInstallationAsync(DeviceInstallation deviceInstallation, CancellationToken token)
            {
                if (string.IsNullOrWhiteSpace(deviceInstallation?.InstallationId) ||
                    string.IsNullOrWhiteSpace(deviceInstallation?.Platform) ||
                    string.IsNullOrWhiteSpace(deviceInstallation?.PushChannel))
                    return false;
    
                var installation = new Installation()
                {
                    InstallationId = deviceInstallation.InstallationId,
                    PushChannel = deviceInstallation.PushChannel,
                    Tags = deviceInstallation.Tags
                };
    
                if (_installationPlatform.TryGetValue(deviceInstallation.Platform, out var platform))
                    installation.Platform = platform;
                else
                    return false;
    
                try
                {
                    await _hub.CreateOrUpdateInstallationAsync(installation, token);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }
    
            public async Task<bool> DeleteInstallationByIdAsync(string installationId, CancellationToken token)
            {
                if (string.IsNullOrWhiteSpace(installationId))
                    return false;
    
                try
                {
                    await _hub.DeleteInstallationAsync(installationId, token);
                }
                catch
                {
                    return false;
                }
    
                return true;
            }
    
            public async Task<bool> RequestNotificationAsync(NotificationRequest notificationRequest, CancellationToken token)
            {
                if ((notificationRequest.Silent &&
                    string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
                    (!notificationRequest.Silent &&
                    (string.IsNullOrWhiteSpace(notificationRequest?.Text)) ||
                    string.IsNullOrWhiteSpace(notificationRequest?.Action)))
                    return false;
    
                var androidPushTemplate = notificationRequest.Silent ?
                    PushTemplates.Silent.Android :
                    PushTemplates.Generic.Android;
    
                var iOSPushTemplate = notificationRequest.Silent ?
                    PushTemplates.Silent.iOS :
                    PushTemplates.Generic.iOS;
    
                var androidPayload = PrepareNotificationPayload(
                    androidPushTemplate,
                    notificationRequest.Text,
                    notificationRequest.Action);
    
                var iOSPayload = PrepareNotificationPayload(
                    iOSPushTemplate,
                    notificationRequest.Text,
                    notificationRequest.Action);
    
                try
                {
                    if (notificationRequest.Tags.Length == 0)
                    {
                        // This will broadcast to all users registered in the notification hub
                        await SendPlatformNotificationsAsync(androidPayload, iOSPayload, token);
                    }
                    else if (notificationRequest.Tags.Length <= 20)
                    {
                        await SendPlatformNotificationsAsync(androidPayload, iOSPayload, notificationRequest.Tags, token);
                    }
                    else
                    {
                        var notificationTasks = notificationRequest.Tags
                            .Select((value, index) => (value, index))
                            .GroupBy(g => g.index / 20, i => i.value)
                            .Select(tags => SendPlatformNotificationsAsync(androidPayload, iOSPayload, tags, token));
    
                        await Task.WhenAll(notificationTasks);
                    }
    
                    return true;
                }
                catch (Exception e)
                {
                    _logger.LogError(e, "Unexpected error sending notification");
                    return false;
                }
            }
    
            string PrepareNotificationPayload(string template, string text, string action) => template
                .Replace("$(alertMessage)", text, StringComparison.InvariantCulture)
                .Replace("$(alertAction)", action, StringComparison.InvariantCulture);
    
            Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, CancellationToken token)
            {
                var sendTasks = new Task[]
                {
                    _hub.SendFcmNativeNotificationAsync(androidPayload, token),
                    _hub.SendAppleNativeNotificationAsync(iOSPayload, token)
                };
    
                return Task.WhenAll(sendTasks);
            }
    
            Task SendPlatformNotificationsAsync(string androidPayload, string iOSPayload, IEnumerable<string> tags, CancellationToken token)
            {
                var sendTasks = new Task[]
                {
                    _hub.SendFcmNativeNotificationAsync(androidPayload, tags, token),
                    _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token)
                };
    
                return Task.WhenAll(sendTasks);
            }
        }
    }
    

    Nota

    La expresión de etiqueta proporcionada para SendTemplateNotificationAsync está limitada a 20 etiquetas. Se limita a 6 para la mayoría de los operadores, pero la expresión solo contiene solicitudes organizativas (||) en este caso. Si hay más de 20 etiquetas en la solicitud, deben dividirse en varias solicitudes. Consulte la documentación expresiones de enrutamiento y etiqueta para obtener más información.

  13. En Startup.cs, actualice el método ConfigureServices para agregar el de NotificationHubsService como una implementación singleton de INotificationService.

    
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
    public void ConfigureServices(IServiceCollection services)
    {
        ...
    
        services.AddSingleton<INotificationService, NotificationHubService>();
    
        services.AddOptions<NotificationHubOptions>()
            .Configure(Configuration.GetSection("NotificationHub").Bind)
            .ValidateDataAnnotations();
    }
    

Creación de la API de notificaciones

  1. ControlHaga clic en en la carpeta Controladores de y elija Nuevo archivo... en el menú Agregar .

  2. Seleccione ASP.NET CoreClase de controlador de API web, escriba NotificationsController para elNombre de y haga clic en Nuevo.

    Nota

    Si sigue con visual Studio 2019, elija el controlador de API de con acciones de lectura y escritura plantilla.

  3. Agregue los siguientes espacios de nombres a la parte superior del archivo.

    using System.ComponentModel.DataAnnotations;
    using System.Net;
    using System.Threading;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using PushDemoApi.Models;
    using PushDemoApi.Services;
    
  4. Actualice el controlador con plantilla para que derive de ControllerBase y esté decorado con el atributo ApiController.

    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    {
        // Templated methods here
    }
    

    Nota

    La clase base Controller proporciona compatibilidad con vistas, pero esto no es necesario en este caso, por lo que ControllerBase se puede usar en su lugar. Si sigue con visual Studio 2019, puede omitir este paso.

  5. Si eligió completar la sección Autenticar clientes de mediante una de clave de API, también debe decorar el NotificationsController de con el atributo Authorize .

    [Authorize]
    
  6. Actualice el constructor para aceptar la instancia registrada de INotificationService como argumento y asignarla a un miembro de solo lectura.

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  7. En launchSettings.json (dentro de la carpeta Propiedades de ), cambie el launchUrl de a api/notifications para que coincida con la dirección URL especificada en el atributo RegistrationsControllerRoute.

  8. Inicie la depuración (CommandEnter) para validar que la aplicación está trabajando con el nuevo NotificationsController de y devuelve un estado de no autorizado 401.

    Nota

    Es posible que Visual Studio no inicie automáticamente la aplicación en el explorador. Usará Postman para probar la API desde este punto.

  9. En una nueva pestaña Postman, establezca la solicitud en GET. Escriba la dirección siguiente reemplazando el marcador de posición applicationUrl por el applicationUrl de https que se encuentra en PropertieslaunchSettings.json.

    <applicationUrl>/api/notifications
    

    Nota

    El applicationUrl de debe ser "" para el perfil predeterminado. Si usa IIS (valor predeterminado en visual Studio 2019 en Windows), debe usar el applicationUrl especificado en el elemento iisSettings en su lugar. Recibirá una respuesta 404 si la dirección es incorrecta.

  10. Si eligió completar la sección autenticar clientes de mediante una clave de API, asegúrese de configurar los encabezados de solicitud para incluir el valor de apikey de .

    Llave Valor
    apikey <your_api_key>
  11. Haga clic en el botón enviar .

    Nota

    Debe recibir un estado de de 200 OK con algún contenido de JSON .

    Si recibe una advertencia de comprobación de certificados SSL , puede cambiar la comprobación del certificado SSL de solicitud de Postman en la configuración de Configuración.

  12. Reemplace los métodos de clase con plantilla en NotificationsController.cs por el código siguiente.

    [HttpPut]
    [Route("installations")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> UpdateInstallation(
        [Required]DeviceInstallation deviceInstallation)
    {
        var success = await _notificationService
            .CreateOrUpdateInstallationAsync(deviceInstallation, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpDelete()]
    [Route("installations/{installationId}")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<ActionResult> DeleteInstallation(
        [Required][FromRoute]string installationId)
    {
        var success = await _notificationService
            .DeleteInstallationByIdAsync(installationId, CancellationToken.None);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    
    [HttpPost]
    [Route("requests")]
    [ProducesResponseType((int)HttpStatusCode.OK)]
    [ProducesResponseType((int)HttpStatusCode.BadRequest)]
    [ProducesResponseType((int)HttpStatusCode.UnprocessableEntity)]
    public async Task<IActionResult> RequestPush(
        [Required]NotificationRequest notificationRequest)
    {
        if ((notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Action)) ||
            (!notificationRequest.Silent &&
            string.IsNullOrWhiteSpace(notificationRequest?.Text)))
            return new BadRequestResult();
    
        var success = await _notificationService
            .RequestNotificationAsync(notificationRequest, HttpContext.RequestAborted);
    
        if (!success)
            return new UnprocessableEntityResult();
    
        return new OkResult();
    }
    

Creación de la aplicación de API

Ahora creará una de aplicación de API de en de Azure App Service para hospedar el servicio back-end.

  1. Inicie sesión en Azure Portal.

  2. Haga clic en Crear un recursoy, después, busque y elija API Appy haga clic en Crear.

  3. Actualice los campos siguientes y haga clic en Crear.

    Nombre de la aplicación:
    Escriba un nombre único global para API App

    Suscripción:
    Elija el mismo destino suscripción creó el centro de notificaciones.

    grupo de recursos de :
    Elija la misma grupo de recursos creó el centro de notificaciones.

    plan o ubicación de App Service:
    Creación de un nuevo plan de App Service

    Nota

    Cambie de la opción predeterminada a un plan que incluya compatibilidad con ssl. De lo contrario, deberá realizar los pasos adecuados al trabajar con la aplicación móvil para evitar que solicitudes http se bloqueen.

    Application Insights:
    Mantenga la opción sugerida (se creará un nuevo recurso con ese nombre) o elija un recurso existente.

  4. Una vez que se ha aprovisionado la aplicación de API , vaya a ese recurso.

  5. Anote la propiedad URL de en el resumen de de Essentials en la parte superior de la Información general. Esta dirección URL es el punto de conexión de back-end de que se usará más adelante en este tutorial.

    Nota

    La dirección URL usa el nombre de la aplicación de API que especificó anteriormente, con el formato https://<app_name>.azurewebsites.net.

  6. Seleccione configuración en la lista (en Configuración).

  7. Para cada una de las opciones siguientes, haga clic en Nueva configuración de aplicación para escribir el Nombre de y un valor de y, a continuación, haga clic en Aceptar.

    Nombre Valor
    Authentication:ApiKey <api_key_value>
    NotificationHub:Name <hub_name_value>
    NotificationHub:ConnectionString <hub_connection_string_value>

    Nota

    Se trata de la misma configuración que definió anteriormente en la configuración de usuario. Debería poder copiarlos. La configuración Authentication:ApiKey solo es necesaria si decide completar la sección Autenticar clientes con una clave de API. En escenarios de producción, puede ver opciones como Azure KeyVault. Estos se han agregado como configuración de la aplicación para simplificar en este caso.

  8. Una vez agregada toda la configuración de la aplicación, haga clic en Guardary, a continuación, Continuar.

Publicación del servicio back-end

A continuación, implementará la aplicación en la aplicación de API para que sea accesible desde todos los dispositivos.

Nota

Los pasos siguientes son específicos de visual Studio para Mac. Si sigue con visual Studio 2019 en Windows, el flujo de publicación será diferente. Consulte Publicar en Azure App Service en Windows.

  1. Cambie la configuración de de depuración a Release si aún no lo ha hecho.

  2. ControlHaga clic en el proyecto PushDemoApi y, a continuación, elija Publicar en Azure... en el menú Publicar .

  3. Siga el flujo de autenticación si se le pide que lo haga. Use la cuenta que usó en la sección anterior crear la aplicación de API.

  4. Seleccione la aplicación de API de Azure App Service creó anteriormente en la lista como destino de publicación y, a continuación, haga clic en Publicar.

Una vez completado el asistente, publica la aplicación en Azure y, a continuación, abre la aplicación. Tome nota de la dirección URL de si aún no lo ha hecho. Esta dirección URL es el punto de conexión de back-end de que se usa más adelante en este tutorial.

Validación de la API publicada

  1. En Postman abrir una nueva pestaña, establezca la solicitud en PUT y escriba la dirección siguiente. Reemplace el marcador de posición por la dirección base que anotó en la sección anterior publicar el servicio back-end.

    https://<app_name>.azurewebsites.net/api/notifications/installations
    

    Nota

    La dirección base debe tener el formato https://<app_name>.azurewebsites.net/

  2. Si eligió completar la sección autenticar clientes de mediante una clave de API, asegúrese de configurar los encabezados de solicitud para incluir el valor de apikey de .

    Llave Valor
    apikey <your_api_key>
  3. Elija la opción sin formato para lacuerpo de y, después, elija JSON en la lista de opciones de formato y, a continuación, incluya algún marcador de posición contenido de JSON:

    {}
    
  4. Haga clic en Enviar.

    Nota

    Debe recibir un 422 UnprocessableEntity estado del servicio.

  5. Realice los pasos del 1 al 4 de nuevo, pero esta vez especificando el punto de conexión de solicitudes para validar que recibe una respuesta 400 Solicitud incorrecta.

    https://<app_name>.azurewebsites.net/api/notifications/requests
    

Nota

Todavía no es posible probar la API mediante datos de solicitud válidos, ya que esto requerirá información específica de la plataforma de la aplicación móvil cliente.

Creación de una aplicación de Xamarin.Forms multiplataforma

En esta sección, creará una Xamarin.Forms aplicación móvil que implementa notificaciones push de forma multiplataforma.

Permite registrar y anular el registro desde un centro de notificaciones a través del servicio back-end que creó.

Se muestra una alerta cuando se especifica una acción y la aplicación está en primer plano. De lo contrario, las notificaciones aparecen en el Centro de notificaciones.

Nota

Normalmente, realizaría las acciones de registro (y desregistro) durante el punto adecuado del ciclo de vida de la aplicación (o como parte de la experiencia de primera ejecución quizás) sin entradas explícitas de registro o registro del usuario. Sin embargo, este ejemplo requerirá una entrada explícita del usuario para permitir que esta funcionalidad se explore y pruebe más fácilmente.

Creación de la solución de Xamarin.Forms

  1. En visual Studio, cree una nueva solución Xamarin.Forms mediante Aplicación de formularios en blanco como plantilla y escriba PushDemo para elnombre de proyecto de .

    Nota

    En el cuadro de diálogo Configurar la aplicación de formularios en blanco, asegúrese de que el identificador de organización de coincide con el valor que usó anteriormente y que los destinos de android y iOS están comprobados.

  2. ControlHaga clic en en la solución pushDemo de y, a continuación, elija Actualizar paquetes NuGet.

  3. Control + Haga clic en en la solución PushDemo y, a continuación, elija Administrar paquetes NuGet..

  4. Busque Newtonsoft.Json y asegúrese de que está activada.

  5. Haga clic en Agregar paquetesy, a continuación, haga clic en Aceptar cuando se le pida que acepte los términos de licencia.

  6. Compile y ejecute la aplicación en cada plataforma de destino (Comando + Escriba) para probar que la aplicación con plantilla se ejecuta en los dispositivos.

Implementación de los componentes multiplataforma

  1. ControlHaga clic en en el proyecto PushDemo, elija Nueva carpeta en el menú Agregar y, a continuación, haga clic en Agregar mediante Models como nombre de carpeta .

  2. ControlHaga clic en en la carpeta modelos de y elija Nuevo archivo... en el menú Agregar .

  3. Seleccione General>Clase vacía, escriba DeviceInstallation.csy agregue la siguiente implementación.

    using System.Collections.Generic;
    using Newtonsoft.Json;
    
    namespace PushDemo.Models
    {
        public class DeviceInstallation
        {
            [JsonProperty("installationId")]
            public string InstallationId { get; set; }
    
            [JsonProperty("platform")]
            public string Platform { get; set; }
    
            [JsonProperty("pushChannel")]
            public string PushChannel { get; set; }
    
            [JsonProperty("tags")]
            public List<string> Tags { get; set; } = new List<string>();
        }
    }
    
  4. Agregue un de enumeración vacía a la carpeta Models denominada PushDemoAction.cs con la siguiente implementación.

    namespace PushDemo.Models
    {
        public enum PushDemoAction
        {
            ActionA,
            ActionB
        }
    }
    
  5. Agregue una nueva carpeta al proyecto de PushDemo denominado Services, a continuación, agregue una clase vacía a esa carpeta denominada ServiceContainer.cs con la siguiente implementación.

    using System;
    using System.Collections.Generic;
    
    namespace PushDemo.Services
    {
       public static class ServiceContainer
       {
           static readonly Dictionary<Type, Lazy<object>> services
               = new Dictionary<Type, Lazy<object>>();
    
           public static void Register<T>(Func<T> function)
               => services[typeof(T)] = new Lazy<object>(() => function());
    
           public static T Resolve<T>()
               => (T)Resolve(typeof(T));
    
           public static object Resolve(Type type)
           {
               {
                   if (services.TryGetValue(type, out var service))
                       return service.Value;
    
                   throw new KeyNotFoundException($"Service not found for type '{type}'");
               }
           }
       }
    }
    

    Nota

    Se trata de una versión recortada de la clase ServiceContainer del repositorio de XamCAT de . Se usará como contenedor ioC ligero (inversión de control).

  6. Agregue un interfaz vacía a la carpeta Services denominada IDeviceInstallationService.csy agregue el código siguiente.

    using PushDemo.Models;
    
    namespace PushDemo.Services
    {
        public interface IDeviceInstallationService
        {
            string Token { get; set; }
            bool NotificationsSupported { get; }
            string GetDeviceId();
            DeviceInstallation GetDeviceInstallation(params string[] tags);
        }
    }
    

    Nota

    Cada destino implementará y arrancará esta interfaz más adelante para proporcionar la funcionalidad específica de la plataforma y DeviceInstallation información requerida por el servicio back-end.

  7. Agregue otra interfaz vacía a la carpeta Services denominada INotificationRegistrationService.csy agregue el código siguiente.

    using System.Threading.Tasks;
    
    namespace PushDemo.Services
    {
        public interface INotificationRegistrationService
        {
            Task DeregisterDeviceAsync();
            Task RegisterDeviceAsync(params string[] tags);
            Task RefreshRegistrationAsync();
        }
    }
    

    Nota

    Esto controlará la interacción entre el cliente y el servicio back-end.

  8. Agregue otro interfaz vacía a la carpeta Services Services denominada INotificationActionService.csy agregue el código siguiente.

    namespace PushDemo.Services
    {
        public interface INotificationActionService
        {
            void TriggerAction(string action);
        }
    }
    

    Nota

    Esto se usa como un mecanismo sencillo para centralizar el control de las acciones de notificación.

  9. Agregue una interfaz vacía a la carpeta Services denominada IPushDemoNotificationActionService.cs que deriva de laINotificationActionService , con la siguiente implementación.

    using System;
    using PushDemo.Models;
    
    namespace PushDemo.Services
    {
        public interface IPushDemoNotificationActionService : INotificationActionService
        {
            event EventHandler<PushDemoAction> ActionTriggered;
        }
    }
    

    Nota

    Este tipo es específico de la aplicación PushDemo y usa la enumeración PushDemoAction para identificar la acción que se desencadena de forma fuerte.

  10. Agregue un de clase vacía a la carpeta de Services denominada NotificationRegistrationService.cs que implementa el INotificationRegistrationService con el código siguiente.

    using System;
    using System.Net.Http;
    using System.Text;
    using System.Threading.Tasks;
    using Newtonsoft.Json;
    using PushDemo.Models;
    using Xamarin.Essentials;
    
    namespace PushDemo.Services
    {
        public class NotificationRegistrationService : INotificationRegistrationService
        {
            const string RequestUrl = "api/notifications/installations";
            const string CachedDeviceTokenKey = "cached_device_token";
            const string CachedTagsKey = "cached_tags";
    
            string _baseApiUrl;
            HttpClient _client;
            IDeviceInstallationService _deviceInstallationService;
    
            public NotificationRegistrationService(string baseApiUri, string apiKey)
            {
                _client = new HttpClient();
                _client.DefaultRequestHeaders.Add("Accept", "application/json");
                _client.DefaultRequestHeaders.Add("apikey", apiKey);
    
                _baseApiUrl = baseApiUri;
            }
    
            IDeviceInstallationService DeviceInstallationService
                => _deviceInstallationService ??
                    (_deviceInstallationService = ServiceContainer.Resolve<IDeviceInstallationService>());
    
            public async Task DeregisterDeviceAsync()
            {
                var cachedToken = await SecureStorage.GetAsync(CachedDeviceTokenKey)
                    .ConfigureAwait(false);
    
                if (cachedToken == null)
                    return;
    
                var deviceId = DeviceInstallationService?.GetDeviceId();
    
                if (string.IsNullOrWhiteSpace(deviceId))
                    throw new Exception("Unable to resolve an ID for the device.");
    
                await SendAsync(HttpMethod.Delete, $"{RequestUrl}/{deviceId}")
                    .ConfigureAwait(false);
    
                SecureStorage.Remove(CachedDeviceTokenKey);
                SecureStorage.Remove(CachedTagsKey);
            }
    
            public async Task RegisterDeviceAsync(params string[] tags)
            {
                var deviceInstallation = DeviceInstallationService?.GetDeviceInstallation(tags);
    
                await SendAsync<DeviceInstallation>(HttpMethod.Put, RequestUrl, deviceInstallation)
                    .ConfigureAwait(false);
    
                await SecureStorage.SetAsync(CachedDeviceTokenKey, deviceInstallation.PushChannel)
                    .ConfigureAwait(false);
    
                await SecureStorage.SetAsync(CachedTagsKey, JsonConvert.SerializeObject(tags));
            }
    
            public async Task RefreshRegistrationAsync()
            {
                var cachedToken = await SecureStorage.GetAsync(CachedDeviceTokenKey)
                    .ConfigureAwait(false);
    
                var serializedTags = await SecureStorage.GetAsync(CachedTagsKey)
                    .ConfigureAwait(false);
    
                if (string.IsNullOrWhiteSpace(cachedToken) ||
                    string.IsNullOrWhiteSpace(serializedTags) ||
                    string.IsNullOrWhiteSpace(DeviceInstallationService.Token) ||
                    cachedToken == DeviceInstallationService.Token)
                    return;
    
                var tags = JsonConvert.DeserializeObject<string[]>(serializedTags);
    
                await RegisterDeviceAsync(tags);
            }
    
            async Task SendAsync<T>(HttpMethod requestType, string requestUri, T obj)
            {
                string serializedContent = null;
    
                await Task.Run(() => serializedContent = JsonConvert.SerializeObject(obj))
                    .ConfigureAwait(false);
    
                await SendAsync(requestType, requestUri, serializedContent);
            }
    
            async Task SendAsync(
                HttpMethod requestType,
                string requestUri,
                string jsonRequest = null)
            {
                var request = new HttpRequestMessage(requestType, new Uri($"{_baseApiUrl}{requestUri}"));
    
                if (jsonRequest != null)
                    request.Content = new StringContent(jsonRequest, Encoding.UTF8, "application/json");
    
                var response = await _client.SendAsync(request).ConfigureAwait(false);
    
                response.EnsureSuccessStatusCode();
            }
        }
    }
    

    Nota

    El argumento apiKey solo es necesario si eligió completar la sección autenticar clientes mediante una clave de API sección.

  11. Agregue un de clase vacía a la carpeta services de denominada PushDemoNotificationActionService.cs implementar el IPushDemoNotificationActionService con el código siguiente.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using PushDemo.Models;
    
    namespace PushDemo.Services
    {
        public class PushDemoNotificationActionService : IPushDemoNotificationActionService
        {
            readonly Dictionary<string, PushDemoAction> _actionMappings = new Dictionary<string, PushDemoAction>
            {
                { "action_a", PushDemoAction.ActionA },
                { "action_b", PushDemoAction.ActionB }
            };
    
            public event EventHandler<PushDemoAction> ActionTriggered = delegate { };
    
            public void TriggerAction(string action)
            {
                if (!_actionMappings.TryGetValue(action, out var pushDemoAction))
                    return;
    
                List<Exception> exceptions = new List<Exception>();
    
                foreach (var handler in ActionTriggered?.GetInvocationList())
                {
                    try
                    {
                        handler.DynamicInvoke(this, pushDemoAction);
                    }
                    catch (Exception ex)
                    {
                        exceptions.Add(ex);
                    }
                }
    
                if (exceptions.Any())
                    throw new AggregateException(exceptions);
            }
        }
    }
    
  12. Agregue una clase vacía al proyecto PushDemo denominado Config.cs con la siguiente implementación.

    namespace PushDemo
    {
        public static partial class Config
        {
            public static string ApiKey = "API_KEY";
            public static string BackendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT";
        }
    }
    

    Nota

    Esto se usa como una manera sencilla de mantener los secretos fuera del control de código fuente. Puede reemplazar estos valores como parte de una compilación automatizada o invalidarlos mediante una clase parcial local. Lo hará en el paso siguiente.

    El campo ApiKey solo es necesario si eligió completar la sección autenticar clientes mediante una clave de API sección.

  13. Agregue otra clase vacía al proyecto PushDemo esta vez llamado Config.local_secrets.cs con la siguiente implementación.

    namespace PushDemo
    {
        public static partial class Config
        {
            static Config()
            {
                ApiKey = "<your_api_key>";
                BackendServiceEndpoint = "<your_api_app_url>";
            }
        }
    }
    

    Nota

    Reemplace los valores de marcador de posición por los suyos propios. Debe haber tomado nota de estos al compilar el servicio back-end. La dirección URL de de la aplicación de API de debe ser . No olvide agregar *.local_secrets.* al archivo gitignore para evitar confirmar este archivo.

    El campo ApiKey solo es necesario si eligió completar la sección autenticar clientes mediante una clave de API sección.

  14. Agregue un clase vacía al proyecto pushDemo denominado Bootstrap.cs con la siguiente implementación.

    using System;
    using PushDemo.Services;
    
    namespace PushDemo
    {
        public static class Bootstrap
        {
            public static void Begin(Func<IDeviceInstallationService> deviceInstallationService)
            {
                ServiceContainer.Register(deviceInstallationService);
    
                ServiceContainer.Register<IPushDemoNotificationActionService>(()
                    => new PushDemoNotificationActionService());
    
                ServiceContainer.Register<INotificationRegistrationService>(()
                    => new NotificationRegistrationService(
                        Config.BackendServiceEndpoint,
                        Config.ApiKey));
            }
        }
    }
    

    Nota

    Cada plataforma llamará al método Begin cuando la aplicación se inicie pasando una implementación específica de la plataforma de IDeviceInstallationService.

    Solo se requiere el argumento del constructorapiKey notificationRegistrationService si eligió completar la sección autenticar clientes de mediante una clave de API sección.

Implementación de la interfaz de usuario multiplataforma

  1. En el proyecto PushDemo, abra MainPage.xaml y reemplace el control StackLayout por lo siguiente.

    <StackLayout VerticalOptions="EndAndExpand"  
                 HorizontalOptions="FillAndExpand"
                 Padding="20,40">
        <Button x:Name="RegisterButton"
                Text="Register"
                Clicked="RegisterButtonClicked" />
        <Button x:Name="DeregisterButton"
                Text="Deregister"
                Clicked="DeregisterButtonClicked" />
    </StackLayout>
    
  2. Ahora, en MainPage.xaml.cs, agregue un campo de respaldo de solo lectura para almacenar una referencia a la implementación de INotificationRegistrationService.

    readonly INotificationRegistrationService _notificationRegistrationService;
    
  3. En el constructor mainPage de , resuelva la implementación de INotificationRegistrationService mediante el serviceContainer de y asígnelo al campo de respaldo de notificationRegistrationService.

    public MainPage()
    {
        InitializeComponent();
    
        _notificationRegistrationService =
            ServiceContainer.Resolve<INotificationRegistrationService>();
    }
    
  4. Implemente los controladores de eventos para los botones de RegisterButton y DeregisterButton eventos Clicked que llaman a los métodos de registroDeregistercorrespondientes.

    void RegisterButtonClicked(object sender, EventArgs e)
        => _notificationRegistrationService.RegisterDeviceAsync().ContinueWith((task)
            => { ShowAlert(task.IsFaulted ?
                    task.Exception.Message :
                    $"Device registered"); });
    
    void DeregisterButtonClicked(object sender, EventArgs e)
        => _notificationRegistrationService.DeregisterDeviceAsync().ContinueWith((task)
            => { ShowAlert(task.IsFaulted ?
                    task.Exception.Message :
                    $"Device deregistered"); });
    
    void ShowAlert(string message)
        => MainThread.BeginInvokeOnMainThread(()
            => DisplayAlert("PushDemo", message, "OK").ContinueWith((task)
                => { if (task.IsFaulted) throw task.Exception; }));
    
  5. Ahora en App.xaml.cs, asegúrese de que se hace referencia a los siguientes espacios de nombres.

    using PushDemo.Models;
    using PushDemo.Services;
    using Xamarin.Essentials;
    using Xamarin.Forms;
    
  6. Implemente el controlador de eventos del evento IPushDemoNotificationActionServiceActionTriggered.

    void NotificationActionTriggered(object sender, PushDemoAction e)
        => ShowActionAlert(e);
    
    void ShowActionAlert(PushDemoAction action)
        => MainThread.BeginInvokeOnMainThread(()
            => MainPage?.DisplayAlert("PushDemo", $"{action} action received", "OK")
                .ContinueWith((task) => { if (task.IsFaulted) throw task.Exception; }));
    
  7. En el constructor de App, resuelva la implementación del IPushNotificationActionService mediante el ServiceContainer y suscríbase al evento IPushDemoNotificationActionServiceActionTriggered.

    public App()
    {
        InitializeComponent();
    
        ServiceContainer.Resolve<IPushDemoNotificationActionService>()
            .ActionTriggered += NotificationActionTriggered;
    
        MainPage = new MainPage();
    }
    

    Nota

    Esto es simplemente para demostrar la recepción y propagación de acciones de notificación push. Normalmente, estos se controlarían silenciosamente, por ejemplo, navegando a una vista específica o actualizando algunos datos en lugar de mostrar una alerta a través de la página raíz , MainPage en este caso.

Configuración del proyecto nativo de Android para notificaciones push

Validación del nombre y los permisos del paquete

  1. En PushDemo.Android, abra el Opciones de proyectoaplicación Android en la sección Build.

  2. Compruebe que el nombre del paquete coincide con el valor que usó en el proyecto de Firebase ConsolePushDemo. El nombre del paquete tenía el formato .

  3. Establezca versión mínima de Android en android 8.0 (nivel de API 26) y el versión de Android de destino de en el nivel de API de más reciente.

    Nota

    Solo se admiten los dispositivos que ejecutan nivel de API 26 y versiones posteriores para los fines de este tutorial, pero puede ampliarlos para admitir dispositivos que ejecutan versiones anteriores.

  4. Asegúrese de que los permisos y READ_PHONE_STATE INTERNET están habilitados en Permisos necesarios.

  5. Haga clic en Aceptar

Agregue los paquetes base de Xamarin Google Play Services y Xamarin.Firebase.Messaging

  1. En PushDemo.Android, ControlHaga clic en en la carpeta paquetes de y elija Administrar paquetes NuGet....

  2. Busque Xamarin.GooglePlayServices.Base (no sótano) y asegúrese de que está comprobado.

  3. Busque Xamarin.Firebase.Messaging y asegúrese de que está activada.

  4. Haga clic en Agregar paquetesy, a continuación, haga clic en Aceptar cuando se le pida que acepte los términos de licencia de .

Adición del archivo JSON de Google Services

  1. Control + Haga clic en en el proyecto de PushDemo.Android y, después, elija Archivo existente... en el menú Agregar.

  2. Elija el archivo de google-services.json que descargó anteriormente al configurar el proyecto PushDemo en la consola Firebase, a continuación, haga clic en Abrir.

  3. Cuando se le solicite, elija Copiar el archivo en el directorio.

  4. Control + Haga clic en en el archivo google-services.json desde el proyecto de PushDemo.Android y asegúrese de GoogleServicesJson se establece como acción de compilación.

Controlar las notificaciones push para Android

  1. ControlHaga clic en en el proyecto de , elija nueva carpeta en el menú Agregar de y, a continuación, haga clic en Agregar con Services comonombre de carpeta .

  2. ControlHaga clic en en la carpeta Services y, a continuación, elija Nuevo archivo... en el menú Agregar .

  3. Seleccione Generalclase vacía, escriba DeviceInstallationService.cs para elNombre de y haga clic en Nuevo agregar la siguiente implementación.

    using System;
    using Android.App;
    using Android.Gms.Common;
    using PushDemo.Models;
    using PushDemo.Services;
    using static Android.Provider.Settings;
    
    namespace PushDemo.Droid.Services
    {
        public class DeviceInstallationService : IDeviceInstallationService
        {
            public string Token { get; set; }
    
            public bool NotificationsSupported
                => GoogleApiAvailability.Instance
                    .IsGooglePlayServicesAvailable(Application.Context) == ConnectionResult.Success;
    
            public string GetDeviceId()
                => Secure.GetString(Application.Context.ContentResolver, Secure.AndroidId);
    
            public DeviceInstallation GetDeviceInstallation(params string[] tags)
            {
                if (!NotificationsSupported)
                    throw new Exception(GetPlayServicesError());
    
                if (string.IsNullOrWhiteSpace(Token))
                    throw new Exception("Unable to resolve token for FCM");
    
                var installation = new DeviceInstallation
                {
                    InstallationId = GetDeviceId(),
                    Platform = "fcm",
                    PushChannel = Token
                };
    
                installation.Tags.AddRange(tags);
    
                return installation;
            }
    
            string GetPlayServicesError()
            {
                int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Application.Context);
    
                if (resultCode != ConnectionResult.Success)
                    return GoogleApiAvailability.Instance.IsUserResolvableError(resultCode) ?
                               GoogleApiAvailability.Instance.GetErrorString(resultCode) :
                               "This device is not supported";
    
                return "An error occurred preventing the use of push notifications";
            }
        }
    }
    

    Nota

    Esta clase proporciona un identificador único (mediante Secure.AndroidId) como parte de la carga de registro del centro de notificaciones.

  4. Agregue otro clase vacía a la carpeta services de denominada PushNotificationFirebaseMessagingService.csy agregue la siguiente implementación.

    using Android.App;
    using Android.Content;
    using Firebase.Messaging;
    using PushDemo.Services;
    
    namespace PushDemo.Droid.Services
    {
        [Service]
        [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })]
        public class PushNotificationFirebaseMessagingService : FirebaseMessagingService
        {
            IPushDemoNotificationActionService _notificationActionService;
            INotificationRegistrationService _notificationRegistrationService;
            IDeviceInstallationService _deviceInstallationService;
    
            IPushDemoNotificationActionService NotificationActionService
                => _notificationActionService ??
                    (_notificationActionService =
                    ServiceContainer.Resolve<IPushDemoNotificationActionService>());
    
            INotificationRegistrationService NotificationRegistrationService
                => _notificationRegistrationService ??
                    (_notificationRegistrationService =
                    ServiceContainer.Resolve<INotificationRegistrationService>());
    
            IDeviceInstallationService DeviceInstallationService
                => _deviceInstallationService ??
                    (_deviceInstallationService =
                    ServiceContainer.Resolve<IDeviceInstallationService>());
    
            public override void OnNewToken(string token)
            {
                DeviceInstallationService.Token = token;
    
                NotificationRegistrationService.RefreshRegistrationAsync()
                    .ContinueWith((task) => { if (task.IsFaulted) throw task.Exception; });
            }
    
            public override void OnMessageReceived(RemoteMessage message)
            {
                if(message.Data.TryGetValue("action", out var messageAction))
                    NotificationActionService.TriggerAction(messageAction);
            }
        }
    }
    
  5. En MainActivity.cs, asegúrese de que se han agregado los siguientes espacios de nombres a la parte superior del archivo.

    using System;
    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.OS;
    using Android.Runtime;
    using Firebase.Iid;
    using PushDemo.Droid.Services;
    using PushDemo.Services;
    
  6. En MainActivity.cs, establezca el LaunchMode en SingleTop, por lo que MainActivity no se volverá a crear cuando se abra.

    [Activity(
        Label = "PushDemo",
        LaunchMode = LaunchMode.SingleTop,
        Icon = "@mipmap/icon",
        Theme = "@style/MainTheme",
        MainLauncher = true,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    
  7. Agregue propiedades privadas y los campos de respaldo correspondientes para almacenar una referencia a las implementaciones de IPushNotificationActionService y IDeviceInstallationService.

    IPushDemoNotificationActionService _notificationActionService;
    IDeviceInstallationService _deviceInstallationService;
    
    IPushDemoNotificationActionService NotificationActionService
        => _notificationActionService ??
            (_notificationActionService =
            ServiceContainer.Resolve<IPushDemoNotificationActionService>());
    
    IDeviceInstallationService DeviceInstallationService
        => _deviceInstallationService ??
            (_deviceInstallationService =
            ServiceContainer.Resolve<IDeviceInstallationService>());
    
  8. Implemente la interfaz de IOnSuccessListener de para recuperar y almacenar el token de Firebase.

    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener
    {
        ...
    
        public void OnSuccess(Java.Lang.Object result)
            => DeviceInstallationService.Token =
                result.Class.GetMethod("getToken").Invoke(result).ToString();
    }
    
  9. Agregue un nuevo método denominado ProcessNotificationActions que comprobará si un de intención de determinado tiene un valor adicional denominado acción. Desencadene condicionalmente esa acción mediante la implementación de IPushDemoNotificationActionService de .

    void ProcessNotificationActions(Intent intent)
    {
        try
        {
            if (intent?.HasExtra("action") == true)
            {
                var action = intent.GetStringExtra("action");
    
                if (!string.IsNullOrEmpty(action))
                    NotificationActionService.TriggerAction(action);
            }
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
        }
    }
    
  10. Invalide el método OnNewIntent para llamar al método ProcessNotificationActions.

    protected override void OnNewIntent(Intent intent)
    {
        base.OnNewIntent(intent);
        ProcessNotificationActions(intent);
    }
    

    Nota

    Dado que el LaunchMode de para el de actividad de está establecido en SingleTop, se enviará una intent de a la instancia de actividad de existente a través de la de método onNewIntent en lugar del método OnCreate, por lo que debe controlar una intención entrante en los métodos OnCreate y OnNewIntent.

  11. Actualice el método OnCreate para llamar a Bootstrap.Begin justo después de la llamada a base.OnCreate pasando la implementación específica de la plataforma de IDeviceInstallationService.

    Bootstrap.Begin(() => new DeviceInstallationService());
    
  12. En el mismo método, llame condicionalmente a GetInstanceId en la instancia de FirebaseApp, justo después de la llamada a Bootstrap.Begin, agregando MainActivity como IOnSuccessListener.

    if (DeviceInstallationService.NotificationsSupported)
    {
        FirebaseInstanceId.GetInstance(Firebase.FirebaseApp.Instance)
            .GetInstanceId()
            .AddOnSuccessListener(this);
    }
    
  13. Todavía en OnCreate, llame a ProcessNotificationActions inmediatamente después de la llamada a pasando elintención de actual.

    ...
    
    LoadApplication(new App());
    
    ProcessNotificationActions(Intent);
    

Nota

Debe volver a registrar la aplicación cada vez que la ejecute y detenerla desde una sesión de depuración para continuar recibiendo notificaciones push.

Configuración del proyecto nativo de iOS para notificaciones push

Configuración de Info.plist y Entitlements.plist

  1. Asegúrese de que ha iniciado sesión en la cuenta de desarrollador de Apple en Preferencias de Visual Studio...publicacióncuentas de desarrollador de Apple y el certificado de y perfil de aprovisionamiento se ha descargado. Debe haber creado estos recursos como parte de los pasos anteriores.

  2. En pushDemo.iOS, abra Info.plist y asegúrese de que el BundleIdentifier de coincide con el valor que se usó para el perfil de aprovisionamiento correspondiente en el portal para desarrolladores de Apple . El BundleIdentifier tenía el formato com.<organization>.PushDemo.

  3. En el mismo archivo, establezca versión mínima del sistema en 13.0.

    Nota

    Solo se admiten los dispositivos que ejecutan iOS 13.0 y versiones posteriores para los fines de este tutorial, pero puede ampliarlo para admitir dispositivos que ejecutan versiones anteriores.

  4. Abra el Opciones de proyecto de para PushDemo.iOS (haga doble clic en el proyecto).

  5. En Opciones de proyecto, en Compilación >firma de lote de iOS , asegúrese de que la cuenta de desarrollador esté seleccionada en Team. A continuación, asegúrese de que la opción "Administrar automáticamente la firma" está seleccionada y el certificado de firma y el perfil de aprovisionamiento se seleccionan automáticamente.

    Nota

    Si la de certificado de firma de y perfil de aprovisionamiento no se han seleccionado automáticamente, elija aprovisionamiento manual y, a continuación, haga clic en Opciones de firma de agrupación. Asegúrese de que la equipo de está seleccionada para de identidad de firma y las configuraciones de PushDemo perfil de aprovisionamiento específico está seleccionada para perfil de aprovisionamiento para Configuración de depuración y Release, lo que garantiza que para la plataforma de en ambos casos.

  6. En pushDemo.iOS, abra Entitlements.plist y asegúrese de que habilitar notificaciones push esté activada cuando se vea en la pestaña Derechos. A continuación, asegúrese de que la configuración entorno de APS de esté establecida en de desarrollo cuando se vea en la pestaña origen de .

Control de notificaciones push para iOS

  1. Control + Haga clic en en el proyecto PushDemo.iOS, elija Nueva carpeta en el menú Agregar y, a continuación, haga clic en Agregar mediante Services como nombre de carpeta .

  2. ControlHaga clic en en la carpeta Services y, a continuación, elija Nuevo archivo... en el menú Agregar .

  3. Seleccione Generalclase vacía, escriba DeviceInstallationService.cs para elNombre de y haga clic en Nuevo agregar la siguiente implementación.

    using System;
    using PushDemo.Models;
    using PushDemo.Services;
    using UIKit;
    
    namespace PushDemo.iOS.Services
    {
        public class DeviceInstallationService : IDeviceInstallationService
        {
            const int SupportedVersionMajor = 13;
            const int SupportedVersionMinor = 0;
    
            public string Token { get; set; }
    
            public bool NotificationsSupported
                => UIDevice.CurrentDevice.CheckSystemVersion(SupportedVersionMajor, SupportedVersionMinor);
    
            public string GetDeviceId()
                => UIDevice.CurrentDevice.IdentifierForVendor.ToString();
    
            public DeviceInstallation GetDeviceInstallation(params string[] tags)
            {
                if (!NotificationsSupported)
                    throw new Exception(GetNotificationsSupportError());
    
                if (string.IsNullOrWhiteSpace(Token))
                    throw new Exception("Unable to resolve token for APNS");
    
                var installation = new DeviceInstallation
                {
                    InstallationId = GetDeviceId(),
                    Platform = "apns",
                    PushChannel = Token
                };
    
                installation.Tags.AddRange(tags);
    
                return installation;
            }
    
            string GetNotificationsSupportError()
            {
                if (!NotificationsSupported)
                    return $"This app only supports notifications on iOS {SupportedVersionMajor}.{SupportedVersionMinor} and above. You are running {UIDevice.CurrentDevice.SystemVersion}.";
    
                if (Token == null)
                    return $"This app can support notifications but you must enable this in your settings.";
    
    
                return "An error occurred preventing the use of push notifications";
            }
        }
    }
    

    Nota

    Esta clase proporciona un identificador único (mediante el UIDevice.IdentifierForVendor valor) y la carga de registro del centro de notificaciones.

  4. Agregue una nueva carpeta al proyecto pushDemo.iOS denominado extensiones , a continuación, agregue una clase vacía a esa carpeta denominada NSDataExtensions.cs con la siguiente implementación.

    using System.Text;
    using Foundation;
    
    namespace PushDemo.iOS.Extensions
    {
        internal static class NSDataExtensions
        {
            internal static string ToHexString(this NSData data)
            {
                var bytes = data.ToArray();
    
                if (bytes == null)
                    return null;
    
                StringBuilder sb = new StringBuilder(bytes.Length * 2);
    
                foreach (byte b in bytes)
                    sb.AppendFormat("{0:x2}", b);
    
                return sb.ToString().ToUpperInvariant();
            }
        }
    }
    
  5. En AppDelegate.cs, asegúrese de que se han agregado los siguientes espacios de nombres a la parte superior del archivo.

    using System;
    using System.Diagnostics;
    using System.Threading.Tasks;
    using Foundation;
    using PushDemo.iOS.Extensions;
    using PushDemo.iOS.Services;
    using PushDemo.Services;
    using UIKit;
    using UserNotifications;
    using Xamarin.Essentials;
    
  6. Agregue propiedades privadas y sus respectivos campos de respaldo para almacenar una referencia a la IPushDemoNotificationActionService, INotificationRegistrationServicey implementaciones de IDeviceInstallationService.

    IPushDemoNotificationActionService _notificationActionService;
    INotificationRegistrationService _notificationRegistrationService;
    IDeviceInstallationService _deviceInstallationService;
    
    IPushDemoNotificationActionService NotificationActionService
        => _notificationActionService ??
            (_notificationActionService =
            ServiceContainer.Resolve<IPushDemoNotificationActionService>());
    
    INotificationRegistrationService NotificationRegistrationService
        => _notificationRegistrationService ??
            (_notificationRegistrationService =
            ServiceContainer.Resolve<INotificationRegistrationService>());
    
    IDeviceInstallationService DeviceInstallationService
        => _deviceInstallationService ??
            (_deviceInstallationService =
            ServiceContainer.Resolve<IDeviceInstallationService>());
    
  7. Agregue el método RegisterForRemoteNotifications para registrar la configuración de notificación de usuario y, a continuación, para las notificaciones remotas con APNS .

    void RegisterForRemoteNotifications()
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            var pushSettings = UIUserNotificationSettings.GetSettingsForTypes(
                UIUserNotificationType.Alert |
                UIUserNotificationType.Badge |
                UIUserNotificationType.Sound,
                new NSSet());
    
            UIApplication.SharedApplication.RegisterUserNotificationSettings(pushSettings);
            UIApplication.SharedApplication.RegisterForRemoteNotifications();
        });
    }
    
  8. Agregue el método CompleteRegistrationAsync para establecer el valor de la propiedad . Actualice el registro y almacene en caché el token de dispositivo si se ha actualizado desde que se almacenó por última vez.

    Task CompleteRegistrationAsync(NSData deviceToken)
    {
        DeviceInstallationService.Token = deviceToken.ToHexString();
        return NotificationRegistrationService.RefreshRegistrationAsync();
    }
    
  9. Agregue el método ProcessNotificationActions de para procesar los datos de notificación de de NSDictionary y llamar condicionalmente a NotificationActionService.TriggerAction.

    void ProcessNotificationActions(NSDictionary userInfo)
    {
        if (userInfo == null)
            return;
    
        try
        {
            var actionValue = userInfo.ObjectForKey(new NSString("action")) as NSString;
    
            if (!string.IsNullOrWhiteSpace(actionValue?.Description))
                NotificationActionService.TriggerAction(actionValue.Description);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
    }
    
  10. Invalide el método RegisteredForRemoteNotifications pasando el argumento deviceToken al método CompleteRegistrationAsync.

    public override void RegisteredForRemoteNotifications(
        UIApplication application,
        NSData deviceToken)
        => CompleteRegistrationAsync(deviceToken).ContinueWith((task)
            => { if (task.IsFaulted) throw task.Exception; });
    
  11. Invalide el método receivedRemoteNotification pasando el argumento userInfo al método ProcessNotificationActions.

    public override void ReceivedRemoteNotification(
        UIApplication application,
        NSDictionary userInfo)
        => ProcessNotificationActions(userInfo);
    
  12. Invalide el método FailedToRegisterForRemoteNotifications para registrar el error.

    public override void FailedToRegisterForRemoteNotifications(
        UIApplication application,
        NSError error)
        => Debug.WriteLine(error.Description);
    

    Nota

    Esto es muy un marcador de posición. Querrá implementar el registro y el control de errores adecuados para escenarios de producción.

  13. Actualice el método FinishedLaunching para llamar a Bootstrap.Begin justo después de la llamada a Forms.Init pasando la implementación específica de la plataforma de IDeviceInstallationService.

    Bootstrap.Begin(() => new DeviceInstallationService());
    
  14. En el mismo método, solicite condicionalmente autorización y regístrese para las notificaciones remotas inmediatamente después de Bootstrap.Begin.

    if (DeviceInstallationService.NotificationsSupported)
    {
        UNUserNotificationCenter.Current.RequestAuthorization(
                UNAuthorizationOptions.Alert |
                UNAuthorizationOptions.Badge |
                UNAuthorizationOptions.Sound,
                (approvalGranted, error) =>
                {
                    if (approvalGranted && error == null)
                        RegisterForRemoteNotifications();
                });
    }
    
  15. Todavía en finishedLaunching, llame a ProcessNotificationActions inmediatamente después de la llamada a si las opciones de argumento contienen el UIApplication.LaunchOptionsRemoteNotificationKey pasando el objeto userInfo resultante.

    using (var userInfo = options?.ObjectForKey(
        UIApplication.LaunchOptionsRemoteNotificationKey) as NSDictionary)
            ProcessNotificationActions(userInfo);
    

Prueba de la solución

Ahora puede probar el envío de notificaciones a través del servicio back-end.

Envío de una notificación de prueba

  1. Abra una nueva pestaña en postman.

  2. Establezca la solicitud en POSTy escriba la siguiente dirección:

    https://<app_name>.azurewebsites.net/api/notifications/requests
    
  3. Si eligió completar la sección autenticar clientes de mediante una clave de API, asegúrese de configurar los encabezados de solicitud para incluir el valor de apikey de .

    Llave Valor
    apikey <your_api_key>
  4. Elija la opción sin formato para lacuerpo de y, después, elija JSON en la lista de opciones de formato y, a continuación, incluya algún marcador de posición contenido de JSON:

    {
        "text": "Message from Postman!",
        "action": "action_a"
    }
    
  5. Seleccione el botón código , que se encuentra bajo el botón Guardar de la parte superior derecha de la ventana. La solicitud debe tener un aspecto similar al ejemplo siguiente cuando se muestra para HTML (dependiendo de si ha incluido un encabezado apikey ):

    POST /api/notifications/requests HTTP/1.1
    Host: https://<app_name>.azurewebsites.net
    apikey: <your_api_key>
    Content-Type: application/json
    
    {
        "text": "Message from backend service",
        "action": "action_a"
    }
    
  6. Ejecute la aplicación PushDemo en una o ambas plataformas de destino (Android y de iOS ).

    Nota

    Si está probando en Android asegúrese de que no se está ejecutando en Depuracióno si la aplicación se ha implementado mediante la ejecución de la aplicación, obligue a cerrar la aplicación e iníciela de nuevo desde el iniciador.

  7. En la aplicación PushDemo, pulse en el botón Registrar.

  8. De nuevo en Postman, cierre la ventana generar fragmentos de código (si aún no lo ha hecho) y haga clic en el botón Enviar.

  9. Compruebe que recibe una respuesta de de 200 OK en Postman y la alerta aparece en la aplicación que muestra acción ActionA recibida.

  10. Cierre la aplicación pushDemo y haga clic en el botón Enviar de nuevo en Postman.

  11. Compruebe que recibe una respuesta de de 200 OK en Postman de nuevo. Compruebe que una notificación aparece en el área de notificación de la aplicación pushDemo con el mensaje correcto.

  12. Pulse en la notificación para confirmar que abre la aplicación y muestra la acción ActionA recibida alerta.

  13. De nuevo en Postman, modifique el cuerpo de la solicitud anterior para enviar una notificación silenciosa que especifique action_b en lugar de action_a para la acción valor.

    {
        "action": "action_b",
        "silent": true
    }
    
  14. Con la aplicación abierta, haga clic en el botón Enviar en Postman.

  15. Compruebe que recibe una respuesta de de 200 OK en Postman y que la alerta aparece en la aplicación que muestra acción ActionB recibida en lugar de acción ActionA recibida.

  16. Cierre la aplicación pushDemo y haga clic en el botón Enviar de nuevo en Postman.

  17. Compruebe que recibe una respuesta de 200 OK en Postman y que la notificación silenciosa no aparece en el área de notificación.

Solución de problemas

No hay respuesta del servicio back-end

Al probar localmente, asegúrese de que el servicio back-end se está ejecutando y está usando el puerto correcto.

Si las pruebas con la aplicación de API de Azure , compruebe que el servicio se está ejecutando y se ha implementado y se ha iniciado sin errores.

Asegúrese de comprobar que ha especificado correctamente la dirección base en postman o en la configuración de la aplicación móvil al probar a través del cliente. La dirección base debe ser https://<api_name>.azurewebsites.net/ o https://localhost:5001/ al realizar pruebas localmente.

No recibir notificaciones en Android después de iniciar o detener una sesión de depuración

Asegúrese de volver a registrarse después de iniciar o detener una sesión de depuración. El depurador hará que se genere un nuevo token Firebase. La instalación del centro de notificaciones también debe actualizarse.

Recepción de un código de estado 401 del servicio back-end

Compruebe que va a establecer el encabezado de solicitud apikey de y este valor coincide con el que ha configurado para el servicio back-end.

Si recibe este error al probar localmente, asegúrese de que el valor de clave definido en la configuración del cliente coincide con el valor de autenticación Authentication:ApiKey valor de configuración de usuario usado por la API de .

Si está probando con una aplicación de API de , asegúrese de que el valor de clave del archivo de configuración de cliente coincide con la configuración de la aplicación Authentication:ApiKey que usa en la aplicación de API .

Nota

Si ha creado o cambiado esta configuración después de haber implementado el servicio back-end, debe reiniciar el servicio para que surta efecto.

Si eligió no completar la sección autenticar clientes de mediante una clave de API, asegúrese de no aplicar el atributo Authorize a la clase notificationsController de .

Recepción de un código de estado 404 del servicio back-end

Compruebe que el punto de conexión y el método de solicitud HTTP son correctos. Por ejemplo, los puntos de conexión deben ser:

  • [PUT]https://<api_name>.azurewebsites.net/api/notifications/installations
  • https://<api_name>.azurewebsites.net/api/notifications/installations/<installation_id> [DELETE]
  • [POST]https://<api_name>.azurewebsites.net/api/notifications/requests

O al probar localmente:

  • [PUT]https://localhost:5001/api/notifications/installations
  • https://localhost:5001/api/notifications/installations/<installation_id> [DELETE]
  • [POST]https://localhost:5001/api/notifications/requests

Al especificar la dirección base en la aplicación cliente, asegúrese de que termina con un /. La dirección base debe ser https://<api_name>.azurewebsites.net/ o https://localhost:5001/ al realizar pruebas localmente.

No se puede registrar y se muestra un mensaje de error del centro de notificaciones

Compruebe que el dispositivo de prueba tiene conectividad de red. A continuación, determine el código de estado de respuesta Http estableciendo un punto de interrupción para inspeccionar el valor de propiedad statusCode en el HttpResponse.

Revise las sugerencias de solución de problemas anteriores cuando corresponda en función del código de estado.

Establezca un punto de interrupción en las líneas que devuelven estos códigos de estado específicos para la API correspondiente. A continuación, intente llamar al servicio back-end al depurar localmente.

Valide que el servicio back-end funciona según lo previsto a través de Postman con la carga adecuada. Use la carga real creada por el código de cliente para la plataforma en cuestión.

Revise las secciones de configuración específicas de la plataforma para asegurarse de que no se ha perdido ningún paso. Compruebe que los valores adecuados se resuelven para installation id y token variables para la plataforma adecuada.

No se puede resolver un identificador para el mensaje de error del dispositivo.

Revise las secciones de configuración específicas de la plataforma para asegurarse de que no se ha perdido ningún paso.

Pasos siguientes

Ahora debería tener una aplicación básica de Xamarin.Forms conectada a un centro de notificaciones a través de un servicio back-end y puede enviar y recibir notificaciones.

Es probable que tenga que adaptar el ejemplo usado en este tutorial para ajustarse a su propio escenario. También se recomienda implementar un control de errores más sólido, la lógica de reintento y el registro.

de Visual Studio App Center se pueden incorporar rápidamente en aplicaciones móviles que proporcionan análisis y diagnósticos de para ayudar a solucionar problemas.