Tutorial: Envío de notificaciones de inserción a aplicaciones MAUI de .NET mediante Azure Notification Hubs a través de un servicio back-end
Las notificaciones de inserción envían información desde un sistema back-end a una aplicación cliente. Apple, Google y otras plataformas tienen su propio servicio de notificaciones push (PNS). Azure Notification Hubs le permite centralizar las notificaciones entre plataformas para que la aplicación back-end pueda comunicarse con un único centro, que se encarga de distribuir notificaciones a cada PNS.
Azure Notification Hubs requiere que las aplicaciones se registren con el centro y opcionalmente, defina plantillas o suscríbase a etiquetas:
- La realización de una instalación de dispositivos vincula un identificador PNS a un identificador del Centro de notificaciones de Azure. Para obtener más información sobre los registros, consulte Administración de registros.
- Las plantillas permiten a los dispositivos especificar plantillas de mensajes con parámetros. Los mensajes entrantes se pueden personalizar por dispositivo. Para obtener más información, consulte Plantillas de Notification Hubs.
- Las etiquetas se pueden usar para suscribirse a categorías de mensajes, como noticias, deportes y el tiempo. Para obtener más información, consulte Expresiones de etiqueta y enrutamiento.
En este tutorial, usará Azure Notification Hubs para enviar notificaciones de inserción a una aplicación de interfaz de usuario de aplicación multiplataforma de .NET (.NET MAUI) destinada a Android e iOS. Un back-end de API web de ASP.NET Core se usa para controlar el registro de dispositivos para el cliente y para iniciar una notificación de inserción. Estas operaciones se controlan mediante el paquete NuGet Microsoft.Azure.NotificationHubs. Para obtener más información sobre el enfoque general, consulte Administración de registros desde un back-end.
En este tutorial ha:
- Configure los servicios de notificaciones de inserción y Azure Notification Hub.
- Cree una aplicación back-end de WebAPI de ASP.NET Core.
- Cree una aplicación .NET MAUI.
- Configure la aplicación Android para las notificaciones de inserción.
- Configure la aplicación iOS para notificaciones de inserción.
- Probar la aplicación.
- Solucione los problemas de configuración y configuración.
Requisitos previos
Para completar este tutorial, necesitará lo siguiente:
- Una cuenta de Azure con una suscripción activa.
- Un equipo o Mac que ejecute la versión más reciente de Visual Studio/Visual Studio Code con la carga de trabajo desarrollo de la interfaz de usuario de aplicaciones multiplataforma de .NET y las cargas de trabajo de desarrollo web y ASP.NET instaladas.
En el caso de Android, debe tener lo siguiente:
- Un desarrollador desbloqueó un dispositivo físico o un emulador que ejecuta la API 26+ con Google Play Services instalado.
En el caso de iOS, debe tener lo siguiente:
- Una cuenta de desarrollador de Apple activa.
- Mac con Xcode, junto con un certificado de desarrollador válido instalado en el Llavero.
A continuación, en iOS debe tener:
Un simulador de iOS 16+ que se ejecuta en macOS 13+ en equipos Mac con procesadores Apple Silicon o T2.
O BIEN
Un dispositivo iOS físico registrado en la cuenta de desarrollador (con iOS 13.0 o posterior).
El dispositivo físico registrado en la cuenta de desarrollador de Apple y asociado al certificado.
Importante
El simulador de iOS admite notificaciones remotas en iOS 16+ cuando se ejecuta en macOS 13+ en equipos Mac con procesadores Apple Silicon o T2. Si no cumple estos requisitos de hardware, necesitará una cuenta de desarrollador de Apple activa y un dispositivo físico.
Para seguir este tutorial, debe estar familiarizado con:
- Portal para desarrolladores de Apple
- ASP.NET Core y API Web
- Firebase Cloud Messaging
- Microsoft Azure
Aunque este tutorial tiene como destino Visual Studio, es posible seguirlo con Visual Studio Code en un equipo o Mac. Sin embargo, habrá algunas diferencias que necesitan reconciliar. Por ejemplo, descripciones de la interfaz de usuario y los flujos de trabajo, los nombres de plantilla y la configuración del entorno.
Configuración de servicios de notificaciones de inserción y Azure Notification Hub
En esta sección, configurará Firebase Cloud Messaging y Apple Push Notification Services (APNS). Después, creará y configurará una Azure Notification Hub para trabajar con estos servicios.
Creación de un proyecto de Firebase
Para crear un proyecto de Firebase:
En un explorador web, inicie sesión en la Consola Firebase.
En la consola de Firebase, seleccione el botón Agregar proyecto y cree un nuevo proyecto de Firebase y escriba PushDemo como el Nombre de proyecto.
Nota:
Se generará un nombre único. De manera 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 lo desea, siempre que las ediciones sigan siendo únicas globalmente.
Una vez creado el proyecto, seleccione el logotipo de Android para agregar Firebase a una aplicación Android:
En la página Agregar Firebase a la aplicación Android, escriba un nombre para el paquete, opcionalmente un alias de aplicación y seleccione el botón Registrar aplicación:
En la página Agregar Firebase a la aplicación Android, seleccione el botón Descargar google-services.json y guarde el archivo en una carpeta local antes de seleccionar el botón Siguiente:
En la página Agregar Firebase a la aplicación Android, seleccione el botón Siguiente.
En la página Agregar Firebase a la aplicación Android, seleccione el botón Continuar con la consola.
En la consola de Firebase, seleccione el icono Información general del proyecto y a continuación, seleccione Configuración del proyecto:
En Configuración del proyecto, seleccione la pestaña Cloud Messaging. Verá que Firebase Cloud Messaging API (V1) está habilitado:
En Configuración del proyecto, seleccione la pestaña Cuentas de servicio y a continuación, seleccione el botónGenerar nueva clave privada.
En el cuadro de diálogo Generar nueva clave privada , seleccione el botón Generar clave:
Se descargará un archivo JSON, que contendrá valores que escribirá en el Centro de notificaciones de Azure.
Registro de una aplicación iOS para notificaciones push
Para enviar notificaciones de inserción a una aplicación de iOS, deberá registrar la aplicación con Apple y registrarse para recibir notificaciones de inserción. Para ello, realice los pasos descritos en la siguiente documentación del Centro de notificaciones de Azure:
- Generar el archivo de solicitud de firma de certificado
- Registro de la aplicación para notificaciones de inserción
- Crear un certificado para el centro de notificaciones
Si desea recibir notificaciones de inserción en un dispositivo físico, también deberá Crear un perfil de aprovisionamiento.
Importante
Para recibir notificaciones en segundo plano en iOS, debe agregar el modo en segundo plano de las notificaciones remotas a la aplicación. Para obtener más información, consulte Habilitación de la funcionalidad de notificaciones remotas en developer.apple.com.
Creación de un centro de notificaciones de Azure
Para crear un centro de notificaciones en Azure Portal:
- En un explorador web, inicie sesión en Azure Portal.
- En Azure Portal, haga clic en el botón Crear un recurso y después busque y elija Centro de notificaciones antes de seleccionar el botón Crear.
- En la página Centro de notificaciones, realice los pasos siguientes:
En el campo Suscripción, seleccione el nombre de la suscripción de Azure que desea usar y a continuación, seleccione un grupo de recursos existente o cree uno nuevo.
En el campo Detalles del espacio de nombres, introduzca un nombre único para el nuevo espacio de nombres.
En el campo Detalles del centro de notificaciones, escriba un nombre para el centro de notificaciones. Esto es necesario porque un espacio de nombres contiene uno o varios centros de notificaciones.
En la lista desplegable Ubicación, seleccione un valor que especifique la ubicación en la que desea crear el centro de notificaciones.
Revise la opción Availability Zones. Si elige una región que tiene zonas de disponibilidad, la casilla está activada de manera predeterminada.
Nota:
Las zonas de disponibilidad son una característica de pago, por lo que se agrega una tarifa adicional al nivel.
Elija una opciónRecuperación ante desastres: ninguna, región de recuperación emparejada o región de recuperación flexible. Si elige Región de recuperación emparejada, se mostrará la región de conmutación por error. Si selecciona Región de recuperación flexible, use la lista desplegable para elegir una lista de regiones de recuperación.
Seleccione el botón Crear. Se creará el centro de notificaciones.
- En Azure Portal, vaya al centro de notificaciones recién creado y a continuación, a la hoja Administrar > Directivas de acceso.
- En la hoja Directivas de acceso, anote la cadena de conexión de la directiva de
DefaultFullSharedAccessSignature
. Lo necesitará más adelante al compilar un servicio back-end que se comunique con el centro de notificaciones.
Para más información acerca de cómo crear un centro de notificaciones, consulte Creación de un centro de notificaciones de Azure en Azure Portal.
Configuración de Firebase Cloud Messaging en el centro de notificaciones
Para configurar el centro de notificaciones para comunicarse con Firebase Cloud Messaging:
En Azure Portal, vaya al centro de notificaciones y seleccione la hoja Configuración> Google (FCM v1)
En la hoja Google (FCM v1), escriba los valores de los Clave privada, Correo electrónico de cliente e Id. de proyecto. Estos valores se pueden encontrar en el archivo JSON de clave privada que descargó de Firebase Cloud Messaging:
Campo de Azure Clave JSON Ejemplo de valor JSON Clave privada private_key
Este valor debe comenzar con -----BEGIN PRIVATE KEY-----\n
y terminar con-----END PRIVATE KEY-----\n
.Cliente de correo electrónico client_email
firebase-adminsdk-55sfg@pushdemo-d6ab2.iam.gserviceaccount.com
Id. de proyecto project_id
pushdemo-d6ab2
En la hoja Google (FCM v1), seleccione el botón Guardar.
Configuración de Apple Push Notification Service en el centro de notificaciones
En Azure Portal, vaya al centro de notificaciones y seleccione la hojaConfiguración> de Apple (APNS). A continuación, siga los pasos adecuados en función del enfoque que ha elegido anteriormente al crear un certificado para el centro de notificaciones.
Importante
Al establecer el Modo de aplicación, elija solo Producción si quiere enviar notificaciones de inserción a los usuarios que han comprado la aplicación desde la tienda.
Opción 1: Uso de un certificado de inserción .p12
- En la hoja Apple (APNS), seleccione el modo de autenticación Certificado.
- En la hoja Apple (APNS), seleccione el icono de archivo situado junto al campo Cargar certificado. A continuación, seleccione el archivo .p12 que exportó anteriormente y cárguelo.
- En la hoja Apple (APNS), escriba la contraseña del certificado en el campo Contraseña si es necesario.
- En la hoja Apple (APNS), seleccione el modo de aplicación Sandbox.
- En la hoja Apple (APNS), seleccione el botón Guardar.
Opción 2: Uso de la autenticación basada en tokens
- En la hoja Apple (APNS), seleccione el modo de autenticación Token.
- En la hoja Apple (APNS), escriba los valores que adquirió anteriormente para los campos Id. de clave, Id. de lote, Id de equipo, y Token.
- En la hoja Apple (APNS), seleccione el modo de aplicación Sandbox.
- En la hoja Apple (APNS), seleccione el botón Guardar.
Creación de una aplicación de back-end de API Web de ASP.NET Core
En esta sección creará un back-end de API web de ASP.NET Core para controlar la instalación de dispositivos y enviar notificaciones a la aplicación MAUI de .NET.
Creación de un proyecto de API web
Para crear un proyecto de API web:
En Visual Studio, cree un proyecto de ASP.NET Core Web API:
En el cuadro de diálogo Configurar el nuevo proyecto, asigne al proyecto el nombre PushNotificationsAPI.
En el cuadro de diálogo Información adicional asegurarse de que las casillas Configurar para HTTPS y Usar controladores están habilitadas:
Una vez creado el proyecto, presione F5 para ejecutar el proyecto.
La aplicación está configurada actualmente para usar
WeatherForecastController
comolaunchUrl
, que se establece en el archivo Properties\launchSettings.json. La aplicación se iniciará en un explorador web y mostrará algunos datos JSON.Importante
Al ejecutar un proyecto de ASP.NET Core que usa HTTPS, Visual Studio detectará si el certificado de desarrollo HTTPS de ASP.NET Core está instalado en el almacén de certificados de usuario local y le ofrecerá instalarlo y confiar en él si falta.
Cierre el explorador web.
En Explorador de soluciones, expanda la carpeta Controladores y elimine WeatherForecastController.cs.
En Explorador de soluciones, en la raíz del proyecto, elimine WeatherForecast.cs.
Abra una ventana de comandos y vaya al directorio que contiene el archivo del proyecto. A continuación, ejecute los siguientes comandos:
dotnet user-secrets init dotnet user-secrets set "NotificationHub:Name" <value> dotnet user-secrets set "NotificationHub:ConnectionString" "<value>"
Reemplace los valores del marcador de posición por sus propios valores de nombre y cadena de conexión del Centro de notificaciones de Azure. Estos se pueden encontrar en las siguientes ubicaciones del Centro de notificaciones de Azure:
Valor de configuración Location NotificationHub:Name
Consulte Name en el resumen Essentials en la parte superior de la página de Información general. NotificationHub:ConnectinString
Consulte DefaultFullSharedAccessSignature* en la página Directivas de acceso. Esto configura los valores de configuración local mediante la Herramienta administrador de secretos. Esto desacopla los secretos del Centro de notificaciones de Azure de la solución de Visual Studio para asegurarse de que no terminan en el control de código fuente.
Sugerencia
En escenarios de producción, considere la posibilidad de usar un servicio como Azure KeyVault para almacenar de forma segura la cadena de conexión.
Autenticación de clientes con una clave de API
Para autenticar clientes con una clave de API:
Abra una ventana de comandos y vaya al directorio que contiene el archivo del proyecto. A continuación, ejecute los siguientes comandos:
dotnet user-secrets set "Authentication:ApiKey" <value>
Reemplace el valor del marcador de posición por la clave de API, que puede ser cualquier valor.
En Visual Studio, agregue una nueva carpeta denominada Authentication al proyecto y a continuación, agregue una nueva clase denominada
ApiKeyAuthOptions
a la carpeta Authentication y reemplace su código por el código siguiente:using Microsoft.AspNetCore.Authentication; namespace PushNotificationsAPI.Authentication; public class ApiKeyAuthOptions : AuthenticationSchemeOptions { public const string DefaultScheme = "ApiKey"; public string Scheme => DefaultScheme; public string ApiKey { get; set; } }
En Visual Studio, agregue una nueva clase denominada
ApiKeyAuthHandler
a la carpeta Authentication y reemplace su código por el código siguiente:using Microsoft.AspNetCore.Authentication; using Microsoft.Extensions.Options; using System.Security.Claims; using System.Text.Encodings.Web; namespace PushNotificationsAPI.Authentication; public class ApiKeyAuthHandler : AuthenticationHandler<ApiKeyAuthOptions> { const string ApiKeyIdentifier = "apikey"; public ApiKeyAuthHandler( IOptionsMonitor<ApiKeyAuthOptions> options, ILoggerFactory logger, UrlEncoder encoder) : base(options, logger, encoder) { } 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)); } }
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.
En Visual Studio, agregue una nueva clase denominada
AuthenticationBuilderExtensions
a la carpeta Authentication y reemplace su código por el código siguiente:using Microsoft.AspNetCore.Authentication; namespace PushNotificationsAPI.Authentication; public static class AuthenticationBuilderExtensions { public static AuthenticationBuilder AddApiKeyAuth( this AuthenticationBuilder builder, Action<ApiKeyAuthOptions> configureOptions) { return builder .AddScheme<ApiKeyAuthOptions, ApiKeyAuthHandler>( ApiKeyAuthOptions.DefaultScheme, configureOptions); } }
Este método de extensión se usará para simplificar el código de configuración de middleware en Program.cs.
En Visual Studio, abra Program.cs y actualice el código para configurar la autenticación de clave de API debajo de la llamada al método
builder.Services.AddControllers
:using PushNotificationsAPI.Authentication; builder.Services.AddControllers(); builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme; options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme; }).AddApiKeyAuth(builder.Configuration.GetSection("Authentication").Bind);
En Program.cs, actualice el código debajo del comentario
// Configure the HTTP request pipeline
para llamar a los métodos de extensiónUseRouting
,UseAuthentication
, yMapControllers
:// Configure the HTTP request pipeline. app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
El método de extensión
UseAuthentication
registra el middleware que usa el esquema de autenticación registrado anteriormente.UseAuthentication
se debe llamar a antes de cualquier middleware que dependa de los usuarios que se autentiquen.Nota:
Aunque una clave de API no es tan segura como un token, bastará para este tutorial y se configurará fácilmente a través de Middleware de ASP.NET.
Agregar y configurar servicios
Para agregar y configurar servicios en la aplicación back-end de API web:
En Visual Studio, agregue el paquete NuGet de Microsoft.Azure.NotificationHubs al proyecto. Este paquete NuGet se usa para acceder al centro de notificaciones, encapsulado dentro de un servicio.
En Visual Studio, agregue una nueva carpeta denominada Models al proyecto y a continuación, agregue una nueva clase denominada
PushTemplates
a la carpeta Models y reemplace su código por el código siguiente:namespace PushNotificationsAPI.Models; public class PushTemplates { public class Generic { public const string Android = "{ \"message\" : { \"notification\" : { \"title\" : \"PushDemo\", \"body\" : \"$(alertMessage)\"}, \"data\" : { \"action\" : \"$(alertAction)\" } } }"; public const string iOS = "{ \"aps\" : {\"alert\" : \"$(alertMessage)\"}, \"action\" : \"$(alertAction)\" }"; } public class Silent { public const string Android = "{ \"message\" : { \"data\" : {\"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\"} } }"; public const string iOS = "{ \"aps\" : {\"content-available\" : 1, \"apns-priority\": 5, \"sound\" : \"\", \"badge\" : 0}, \"message\" : \"$(alertMessage)\", \"action\" : \"$(alertAction)\" }"; } }
La clase
PushTemplates
contiene cargas de notificación tokenizadas para las notificaciones de inserción genéricas y silenciosas. Estas cargas se definen fuera de la instalación 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 artículo. En escenarios de producto, considere la posibilidad de usar plantillas personalizadas.En Visual Studio, agregue una nueva clase denominada
DeviceInstallation
a la carpeta Models y reemplace su código por el código siguiente:using System.ComponentModel.DataAnnotations; namespace PushNotificationsAPI.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>(); }
En Visual Studio, agregue una nueva clase denominada
NotificationRequest
a la carpeta Models y reemplace su código por el código siguiente:namespace PushNotificationsAPI.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; } }
En Visual Studio, agregue una nueva clase denominada
NotificationHubOptions
a la carpeta Models y reemplace su código por el código siguiente:using System.ComponentModel.DataAnnotations; namespace PushNotificationsAPI.Models; public class NotificationHubOptions { [Required] public string Name { get; set; } [Required] public string ConnectionString { get; set; } }
En Visual Studio, agregue una nueva carpeta denominada Services al proyecto y a continuación, agregue una nueva interfaz denominada
INotificationService
a la carpeta Services y reemplace su código por el código siguiente:using PushNotificationsAPI.Models; namespace PushNotificationsAPI.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); }
En Visual Studio, agregue una nueva clase denominada
NotificationHubService
a la carpeta Services y reemplace su código por el código siguiente:using Microsoft.Extensions.Options; using Microsoft.Azure.NotificationHubs; using PushNotificationsAPI.Models; namespace PushNotificationsAPI.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.FcmV1).ToLower(), NotificationPlatform.FcmV1 } }; } 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.SendFcmV1NativeNotificationAsync(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.SendFcmV1NativeNotificationAsync(androidPayload, tags, token), _hub.SendAppleNativeNotificationAsync(iOSPayload, tags, token) }; return Task.WhenAll(sendTasks); } }
La expresión de etiqueta proporcionada al método
SendTemplateNotificationsAsync
se limita a 20 etiquetas si solo contienen ORs. De lo contrario, se limitan a 6 etiquetas. Para obtener más información, consulte Expresiones de etiqueta y enrutamiento.En Visual Studio, abra Program.cs y actualice el código para agregar como
NotificationHubService
una implementación singleton de debajo deINotificationService
la llamada al métodobuilder.Services.AddAuthentication
:using PushNotificationsAPI.Authentication; using PushNotificationsAPI.Services; using PushNotificationsAPI.Models; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = ApiKeyAuthOptions.DefaultScheme; options.DefaultChallengeScheme = ApiKeyAuthOptions.DefaultScheme; }).AddApiKeyAuth(builder.Configuration.GetSection("Authentication").Bind); builder.Services.AddSingleton<INotificationService, NotificationHubService>(); builder.Services.AddOptions<NotificationHubOptions>() .Configure(builder.Configuration.GetSection("NotificationHub").Bind) .ValidateDataAnnotations(); var app = builder.Build();
Creación de la API de REST de notificaciones
Para crear la API de REST de notificaciones:
En Visual Studio, agregue un nuevo controlador denominado
NotificationsController
a la carpeta Controladores.Sugerencia
Elija la plantilla Controlador de API con acciones de lectura.
En el archivo NotificationsController.cs, agregue las siguientes instrucciones
using
en la parte superior del archivo:using System.ComponentModel.DataAnnotations; using System.Net; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using PushNotificationsAPI.Models; using PushNotificationsAPI.Services;
En el archivo NotificationsController.cs, agregue el atributo
Authorize
a la claseNotificationsController
:[Authorize] [ApiController] [Route("api/[controller]")] public class NotificationsController : ControllerBase
En el archivo NotificationsController.cs, actualice el constructor
NotificationsContoller
para aceptar la instancia registradaINotificationService
como argumento y asígnela a un miembro de solo lectura:readonly INotificationService _notificationService; public NotificationsController(INotificationService notificationService) { _notificationService = notificationService; }
En el archivo NotificationsContoller.cs, reemplace todos los métodos 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) { // Probably want to ensure deletion even if the connection is broken 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(); }
En el archivo Properties/launchSettings.json , cambie la propiedad
launchUrl
para cada perfil deweatherforecast
aapi/notifications
.
Creación de una clave de API
Ahora creará una aplicación de API en Azure App Service para hospedar el servicio back-end. Esto se puede lograr directamente desde Visual Studio o Visual Studio Code, con la CLI de Azure, Azure PowerShell, la CLI para desarrolladores de Azure y a través de Azure Portal. Para obtener más información, consulte Publicar la aplicación web.
Para crear una aplicación de API en Azure Portal:
En un explorador web, inicie sesión en Azure Portal.
En Azure Portal, haga clic en el botón Crear un recurso y a continuación, busque y elija aplicación de API antes de seleccionar el botón Crear.
En la página Crear aplicación de API, actualice los campos siguientes antes de seleccionar el botón Crear:
Campo Acción Subscription Elija la misma suscripción de destino en la que ha creado el centro de notificaciones. Grupo de recursos Elija el mismo grupo de recursos en el que creó el centro de notificaciones. Nombre Escriba un nombre único global. Pila en tiempo de ejecución Asegúrese de que está seleccionada la versión más reciente de .NET. Una vez aprovisionada la aplicación API , vaya al recurso.
En la página Información general, anote el valor de dominio predeterminado. Esta dirección URL es el punto de conexión de back-end que se consumirá desde la aplicación MAUI de .NET. La dirección URL usará el nombre de la aplicación de API que especificó, con el formato
https://<app_name>.azurewebsites.net
.En Azure Portal, vaya a la hoja Configuración > Variables de entorno y asegúrese de que está seleccionada la pestaña Configuración de la aplicación. A continuación, use el botón Agregar para agregar la siguiente configuración:
NOMBRE Valor Authentication:ApiKey <api_key_value> NotificationHub:Name <hub_name_value> NotificationHub:ConnectionString <hub_connection_string_value> Importante
La configuración de la aplicación
Authentication:ApiKey
se ha agregado por motivos de simplicidad. En escenarios de producción, considere la posibilidad de usar un servicio como Azure KeyVault para almacenar de forma segura la cadena de conexión.Una vez que se hayan escrito todas estas configuraciones, seleccione el botón Aplicar y a continuación, el botónConfirmar.
Publicación del servicio back-end
Para publicar el servicio back-end en Azure App Service:
- En Visual Studio, haga clic con el botón derecho en el proyecto y seleccione Publicar.
- En el Asistente para publicación, seleccione Azure y a continuación, el botón Siguiente.
- En el Asistente para publicación, seleccione Azure App Service (Windows) y a continuación, el botón Siguiente.
- En el asistente Publicar, siga el flujo de autenticación para conectar Visual Studio a su suscripción de Azure y publicar la aplicación.
Visual Studio compila, empaqueta y publica la aplicación en Azure y a continuación, inicia la aplicación en el explorador predeterminado. Para obtener más información, consulte Publicación de una aplicación web de ASP.NET.
Sugerencia
Puede descargar un perfil de publicación para la aplicación en la hoja Información general de la aplicación de API en Azure Portal y a continuación, usar el perfil en Visual Studio para publicar la aplicación.
Validación de la API publicada
Para comprobar que la aplicación de API se ha publicado correctamente, debe usar las herramientas REST que prefiera para enviar una solicitud de POST
a la siguiente dirección:
https://<app_name>.azurewebsites.net/api/notifications/requests
Nota:
La dirección base es https://<app_name>.azurewebsites.net
.
Asegúrese de configurar los encabezados de solicitud para incluir la clave apikey
y su valor, establecer el cuerpo en sin procesar y usar el siguiente contenido JSON de marcador de posición:
{}
Debe recibir una respuesta 400 Bad Request
del servicio.
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 MAUI de .NET.
Para obtener más información acerca de cómo llamar a las API de REST, consulte Uso de archivos .http en Visual Studio y Probar API web con Http Repl. En Visual Studio Code, Cliente REST se puede usar para probar las API de REST.
Crear una aplicación .NET MAUI
En esta sección, creará una aplicación de interfaz de usuario de aplicación multiplataforma (.NET MAUI) de .NET que le permite registrarse para recibir notificaciones de inserción desde un centro de notificaciones a través del servicio back-end y anular el registro.
Para crear la aplicación MAUI de .NET:
En Visual Studio, cree una nueva aplicación MAUI de .NET denominada PushNotificationsDemomediante la Plantilla de proyecto Aplicación MAUI de .NET.
En Visual Studio, agregue una nueva carpeta denominada Models al proyecto MAUI de .NET y agregue una nueva clase denominada
DeviceInstallation
a la carpeta Models y reemplace su código por el código siguiente:using System.Text.Json.Serialization; namespace PushNotificationsDemo.Models; public class DeviceInstallation { [JsonPropertyName("installationId")] public string InstallationId { get; set; } [JsonPropertyName("platform")] public string Platform { get; set; } [JsonPropertyName("pushChannel")] public string PushChannel { get; set; } [JsonPropertyName("tags")] public List<string> Tags { get; set; } = new List<string>(); }
En Visual Studio, agregue una enumeración denominada
PushDemoAction
a la carpeta Models y reemplace su código por el código siguiente:namespace PushNotificationsDemo.Models; public enum PushDemoAction { ActionA, ActionB }
En Visual Studio, agregue una nueva carpeta denominada Services al proyecto MAUI de .NET y a continuación, agregue una nueva interfaz denominada
IDeviceInstallationService
a la carpeta Services y reemplace su código por el código siguiente:using PushNotificationsDemo.Models; namespace PushNotificationsDemo.Services; public interface IDeviceInstallationService { string Token { get; set; } bool NotificationsSupported { get; } string GetDeviceId(); DeviceInstallation GetDeviceInstallation(params string[] tags); }
Esta interfaz se implementará en cada plataforma más adelante para proporcionar la información
DeviceInstallation
requerida por el servicio back-end.En Visual Studio, agregue una interfaz denominada
INotificationRegistrationService
a la carpeta Services y reemplace su código por el código siguiente:namespace PushNotificationsDemo.Services; public interface INotificationRegistrationService { Task DeregisterDeviceAsync(); Task RegisterDeviceAsync(params string[] tags); Task RefreshRegistrationAsync(); }
Esta interfaz controlará la interacción entre el cliente y el servicio back-end.
En Visual Studio, agregue una interfaz denominada
INotificationActionService
a la carpeta Services y reemplace su código por el código siguiente:namespace PushNotificationsDemo.Services; public interface INotificationActionService { void TriggerAction(string action); }
Esta interfaz se usará como un mecanismo sencillo para centralizar el control de las acciones de notificación.
En Visual Studio, agregue una interfaz denominada
IPushDemoNotificationActionService
a la carpeta Services y reemplace su código por el código siguiente:using PushNotificationsDemo.Models; namespace PushNotificationsDemo.Services; public interface IPushDemoNotificationActionService : INotificationActionService { event EventHandler<PushDemoAction> ActionTriggered; }
El tipo
IPushDemoNotificationActionService
es específico de esta aplicación y usa la enumeraciónPushDemoAction
para identificar la acción que se desencadena mediante un enfoque fuertemente tipado.En Visual Studio, agregue una clase denominada
NotificationRegistrationService
a la carpeta Services y reemplace su código por el código siguiente:using System.Text; using System.Text.Json; using PushNotificationsDemo.Models; namespace PushNotificationsDemo.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; IDeviceInstallationService DeviceInstallationService => _deviceInstallationService ?? (_deviceInstallationService = Application.Current.MainPage.Handler.MauiContext.Services.GetService<IDeviceInstallationService>()); public NotificationRegistrationService(string baseApiUri, string apiKey) { _client = new HttpClient(); _client.DefaultRequestHeaders.Add("Accept", "application/json"); _client.DefaultRequestHeaders.Add("apikey", apiKey); _baseApiUrl = baseApiUri; } 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, JsonSerializer.Serialize(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 = JsonSerializer.Deserialize<string[]>(serializedTags); await RegisterDeviceAsync(tags); } async Task SendAsync<T>(HttpMethod requestType, string requestUri, T obj) { string serializedContent = null; await Task.Run(() => serializedContent = JsonSerializer.Serialize(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(); } }
En Visual Studio, agregue una clase denominada
PushDemoNotificationActionService
a la carpeta Services y reemplace su código por el código siguiente:using PushNotificationsDemo.Models; namespace PushNotificationsDemo.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); } }
En Visual Studio, agregue una clase denominada
Config
a la raíz del proyecto y reemplace su código por el código siguiente:namespace PushNotificationsDemo; public static partial class Config { public static string ApiKey = "API_KEY"; public static string BackendServiceEndpoint = "BACKEND_SERVICE_ENDPOINT"; }
La clase
Config
se usa como 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.Importante
Al especificar la dirección base en la aplicación MAUI de .NET, asegúrese de que finaliza con un
/
.En Visual Studio, agregue una clase denominada
Config.local_secrets
a la raíz del proyecto. A continuación, reemplace el código del archivo Config.local_secrets.cs por el código siguiente:namespace PushNotificationsDemo; public static partial class Config { static Config() { ApiKey = "<your_api_key>"; BackendServiceEndpoint = "<your_api_app_url>"; } }
Reemplace los valores de marcador de posición por los valores que eligió al crear el servicio back-end. La dirección URL
BackendServiceEndpoint
debe usar el formatohttps://<api_app_name>.azurewebsites.net/
.Sugerencia
Recuerde agregar
*.local_secrets.*
al archivo.gitignore
para evitar confirmar este archivo en el control de código fuente.
Creación de la interfaz de usuario
Para crear la interfaz de usuario de la aplicación:
En Visual Studio, abra MainPage.xaml y reemplace
VerticalStackLayout
y sus elementos secundarios por el código XAML siguiente:<VerticalStackLayout Margin="20" Spacing="6"> <Button x:Name="registerButton" Text="Register" Clicked="OnRegisterButtonClicked" /> <Button x:Name="deregisterButton" Text="Deregister" Clicked="OnDeregisterButtonClicked" /> </VerticalStackLayout>
En Visual Studio, abra MainPage.xaml.cs y agregue una instrucción
using
para el espacio de nombresPushNotificationsDemo.Services
:using PushNotificationsDemo.Services;
En MainPage.xaml.cs, agregue un campo de respaldo
readonly
para almacenar una referencia a la implementación deINotificationRegistrationService
:readonly INotificationRegistrationService _notificationRegistrationService;
En el constructor
MainPage
, resuelva la implementación deINotificationRegistrationService
y asígnela al campo de respaldo de_notificationRegistrationService
:public MainPage(INotificationRegistrationService service) { InitializeComponent(); _notificationRegistrationService = service; }
En la clase
MainPage
, implemente los controladores de eventosOnRegisterButtonClicked
yOnDeregisterButtonClicked
, llamando a los métodos register y desregister correspondientes en el objetoINotificationRegistrationService
:void OnRegisterButtonClicked(object sender, EventArgs e) { _notificationRegistrationService.RegisterDeviceAsync() .ContinueWith((task) => { ShowAlert(task.IsFaulted ? task.Exception.Message : $"Device registered"); }); } void OnDeregisterButtonClicked(object sender, EventArgs e) { _notificationRegistrationService.DeregisterDeviceAsync() .ContinueWith((task) => { ShowAlert(task.IsFaulted ? task.Exception.Message : $"Device deregistered"); }); } void ShowAlert(string message) { MainThread.BeginInvokeOnMainThread(() => { DisplayAlert("Push notifications demo", message, "OK") .ContinueWith((task) => { if (task.IsFaulted) throw task.Exception; }); }); }
Importante
En la aplicación, el registro y el des-registro se realizan en respuesta a la entrada del usuario, para permitir que esta funcionalidad se explore y pruebe más fácilmente. En una aplicación de producción, normalmente realizaría las acciones de registro y des registro durante el punto adecuado del ciclo de vida de la aplicación, sin necesidad de especificar explícitamente el usuario.
En Visual Studio, abra App.xaml.cs y agregue las siguientes instrucciones
using
:using PushNotificationsDemo.Models; using PushNotificationsDemo.Services;
En App.xaml.cs, agregue un campo de respaldo
readonly
para almacenar una referencia a la implementaciónIPushDemoNotificationActionService
:readonly IPushDemoNotificationActionService _actionService;
En el constructor
App
, resuelva la implementación deIPushDemoNotificationActionService
y asígnela al campo de respaldo_actionService
y suscríbase al eventoIPushDemoNotificationActionService.ActionTriggered
:public App(IPushDemoNotificationActionService service) { InitializeComponent(); _actionService = service; _actionService.ActionTriggered += NotificationActionTriggered; MainPage = new AppShell(); }
En la clase
App
, implemente el controlador de eventos para el eventoIPushDemoNotificationActionService.ActionTriggered
:void NotificationActionTriggered(object sender, PushDemoAction e) { ShowActionAlert(e); } void ShowActionAlert(PushDemoAction action) { MainThread.BeginInvokeOnMainThread(() => { MainPage?.DisplayAlert("Push notifications demo", $"{action} action received.", "OK") .ContinueWith((task) => { if (task.IsFaulted) throw task.Exception; }); }); }
El controlador de eventos del evento
ActionTriggered
muestra la recepción y propagación de acciones de notificación de inserción. Normalmente, estos se controlarían de forma silenciosa, por ejemplo, navegando a una vista específica o actualizando algunos datos en lugar de mostrar una alerta.
Configuración de la aplicación Android
Para configurar la aplicación .NET MAUI en Android para recibir y procesar notificaciones de inserción:
En Visual Studio, agregue el paquete NuGet Xamarin.Firebase.Messaging al proyecto de aplicación MAUI de .NET.
En Visual Studio, agregue el archivo google-services.json a la carpeta Platforms/Android del proyecto de aplicación MAUI de .NET. Una vez agregado el archivo al proyecto, debe haberse agregado con una acción de compilación de
GoogleServicesJson
:<ItemGroup Condition="'$(TargetFramework)' == 'net8.0-android'"> <GoogleServicesJson Include="Platforms\Android\google-services.json" /> </ItemGroup>
Sugerencia
No olvide agregar
google-services.json
al archivo.gitignore
para evitar confirmar este archivo en el control de código fuente.En Visual Studio, edite el archivo de proyecto (*.csproj) y establezca
SupportedOSPlatformVersion
para Android en 26.0:<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">26.0</SupportedOSPlatformVersion>
Google realizó cambios en los canales de notificación de Android en la API 26. Para obtener más información, consulte Canales de notificación en developer.android.com.
En la carpeta Platforms/Android del proyecto, agregue una nueva clase denominada
DeviceInstallationService
y reemplace su código por el código siguiente:using Android.Gms.Common; using PushNotificationsDemo.Models; using PushNotificationsDemo.Services; using static Android.Provider.Settings; namespace PushNotificationsDemo.Platforms.Android; public class DeviceInstallationService : IDeviceInstallationService { public string Token { get; set; } public bool NotificationsSupported => GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Platform.AppContext) == ConnectionResult.Success; public string GetDeviceId() => Secure.GetString(Platform.AppContext.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 FCMv1."); var installation = new DeviceInstallation { InstallationId = GetDeviceId(), Platform = "fcmv1", PushChannel = Token }; installation.Tags.AddRange(tags); return installation; } string GetPlayServicesError() { int resultCode = GoogleApiAvailability.Instance.IsGooglePlayServicesAvailable(Platform.AppContext); if (resultCode != ConnectionResult.Success) return GoogleApiAvailability.Instance.IsUserResolvableError(resultCode) ? GoogleApiAvailability.Instance.GetErrorString(resultCode) : "This device isn't supported."; return "An error occurred preventing the use of push notifications."; } }
Esta clase proporciona un identificador único, mediante el valor
Secure.AndroidId
y la carga de registro del centro de notificaciones.En la carpeta Platforms/Android del proyecto, agregue una nueva clase denominada
PushNotificationFirebaseMessagingService
y reemplace su código por el código siguiente:using Android.App; using Firebase.Messaging; using PushNotificationsDemo.Services; namespace PushNotificationsDemo.Platforms.Android; [Service(Exported = false)] [IntentFilter(new[] { "com.google.firebase.MESSAGING_EVENT" })] public class PushNotificationFirebaseMessagingService : FirebaseMessagingService { IPushDemoNotificationActionService _notificationActionService; INotificationRegistrationService _notificationRegistrationService; IDeviceInstallationService _deviceInstallationService; int _messageId; IPushDemoNotificationActionService NotificationActionService => _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>()); INotificationRegistrationService NotificationRegistrationService => _notificationRegistrationService ?? (_notificationRegistrationService = IPlatformApplication.Current.Services.GetService<INotificationRegistrationService>()); IDeviceInstallationService DeviceInstallationService => _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<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) { base.OnMessageReceived(message); if (message.Data.TryGetValue("action", out var messageAction)) NotificationActionService.TriggerAction(messageAction); } }
Esta clase tiene un atributo
IntentFilter
que incluye el filtrocom.google.firebase.MESSAGING_EVENT
. Este filtro permite a Android pasar mensajes entrantes a esta clase para su procesamiento.Para obtener información acerca del formato de mensaje Firebase Cloud Messaging, consulte Acerca de los mensajes de FCM en developer.android.com.
En Visual Studio, abra el archivo MainActivity.cs en la carpeta Platforms/Android y agregue las siguientes instrucciones
using
:using Android.App; using Android.Content; using Android.Content.PM; using Android.OS; using PushNotificationsDemo.Services; using Firebase.Messaging;
En la clase
MainActivity
, establezca elLaunchMode
enSingleTop
para que elMainActivity
no se vuelva a crear cuando se abra:[Activity( Theme = "@style/Maui.SplashTheme", MainLauncher = true, LaunchMode = LaunchMode.SingleTop, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
En la clase
MainActivity
, agregue campos de respaldo para almacenar referencias a las implementaciones deIPushDemoNotificationActionService
yIDeviceInstallationService
:IPushDemoNotificationActionService _notificationActionService; IDeviceInstallationService _deviceInstallationService;
En la clase
MainActivity
, agregueNotificationActionService
yDeviceInstallationService
propiedades privadas que recuperen sus implementaciones concretas del contenedor de inserción de dependencias de la aplicación:IPushDemoNotificationActionService NotificationActionService => _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>()); IDeviceInstallationService DeviceInstallationService => _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
En la clase
MainActivity
, implemente la interfazAndroid.Gms.Tasks.IOnSuccessListener
para recuperar y almacenar el token de Firebase:public class MainActivity : MauiAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener { public void OnSuccess(Java.Lang.Object result) { DeviceInstallationService.Token = result.ToString(); } }
En la clase
MainActivity
, agregue el métodoProcessNotificationActions
que comprobará si unIntent
determinado tiene un valor adicional denominadoaction
, y a continuación, desencadene condicionalmente eseaction
mediante la implementación deIPushDemoNotificationActionService
:void ProcessNotificationsAction(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); } }
En la clase
MainActivity
, invalide el métodoOnNewIntent
para llamar al métodoProcessNotificationActions
:protected override void OnNewIntent(Intent? intent) { base.OnNewIntent(intent); ProcessNotificationsAction(intent); }
Dado que el
LaunchMode
de laActivity
se establece enSingleTop
, se enviará unaIntent
a la instancia deActivity
existente a través de la invalidación deOnNewIntent
, en lugar del métodoOnCreate
. Por lo tanto, debe controlar una intención entrante enOnNewIntent
yOnCreate
.En la clase
MainActivity
, invalide el métodoOnCreate
para llamar al métodoProcessNotificationActions
y para recuperar el token de Firebase, agregandoMainActivity
comoIOnSuccessListener
:protected override void OnCreate(Bundle? savedInstanceState) { base.OnCreate(savedInstanceState); if (DeviceInstallationService.NotificationsSupported) FirebaseMessaging.Instance.GetToken().AddOnSuccessListener(this); ProcessNotificationsAction(Intent); }
Nota:
La aplicación debe volver a registrarse cada vez que la ejecute y detenerla de una sesión de depuración para seguir recibiendo notificaciones de inserción.
En Visual Studio, agregue el permiso
POST_NOTIFICATIONS
al archivo AndroidManifest.xml en la carpeta Platforms/Android:<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
Para obtener más información acerca del permiso, consulte Permiso de tiempo de ejecución de notificaciones en developer.android.com.
En Visual Studio, abra MainPage.xaml.cs y agregue el código siguiente a la clase
MainPage
:#if ANDROID protected override async void OnAppearing() { base.OnAppearing(); PermissionStatus status = await Permissions.RequestAsync<Permissions.PostNotifications>(); } #endif
Este código se ejecuta en Android cuando aparece
MainPage
, y solicita al usuario que conceda el permisoPOST_NOTIFICATIONS
. Para obtener más información sobre los permisos .NET MAUI, consulte Permisos.
Configuración de la aplicación iOS
El simulador de iOS admite notificaciones remotas en iOS 16+ cuando se ejecuta en macOS 13+ en equipos Mac con procesadores Apple Silicon o T2. Cada simulador genera tokens de registro que son únicos para la combinación de ese simulador y el hardware Mac en el que se ejecuta.
Importante
El simulador admite el entorno de espacio aislado de Apple Push Notification Service.
En las instrucciones siguientes se supone que usa hardware que admite la recepción de notificaciones remotas en un simulador de iOS. Si no es así, tendrá que ejecutar la aplicación de iOS en un dispositivo físico, lo que requerirá que cree un perfil de aprovisionamiento para la aplicación que incluya la funcionalidad notificaciones de inserción. A continuación, deberá asegurarse de que la aplicación se compila mediante el certificado y el perfil de aprovisionamiento. Para obtener más información acerca de cómo hacerlo, consulte Configuración de la aplicación iOS para que funcione con Azure Notification Hubs, y después siga las instrucciones que se indican a continuación.
Para configurar la aplicación .NET MAUI en iOS para recibir y procesar notificaciones de inserción:
En Visual Studio, edite el archivo de proyecto (*.csproj) y establezca
SupportedOSPlatformVersion
para iOS en 13.0:<SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">13.0</SupportedOSPlatformVersion>
Apple realizó cambios en su servicio de inserción en iOS 13. Para más información, consulte Actualizaciones de Azure Notification Hubs para iOS 13.
En Visual Studio, agregue un archivo Entitlements.plist a la carpeta Platforms/iOS del proyecto y agregue el siguiente XML al archivo:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>aps-environment</key> <string>development</string> </dict> </plist>
Esto establece el derecho de entorno APS y especifica el uso del entorno de desarrollo del servicio Apple Push Notification. En las aplicaciones de producción, este valor de derecho debe establecerse en
production
. Para obtener más información acerca de este derecho, consulte APS Derecho de entorno en developer.apple.com.Para obtener más información acerca de cómo agregar un archivo de derechos, consulte Derechos de iOS.
En Visual Studio, agregue una nueva clase denominada
DeviceInstallationService
a la carpeta Platforms/iOS del proyecto y agregue el código siguiente al archivo:using PushNotificationsDemo.Services; using PushNotificationsDemo.Models; using UIKit; namespace PushNotificationsDemo.Platforms.iOS; 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"; } }
Esta clase proporciona un identificador único, mediante el valor
UIDevice.IdentifierForVendor
y la carga de registro del centro de notificaciones.En Visual Studio, agregue una nueva clase denominada
NSDataExtensions
a la carpeta Platforms/iOS del proyecto y agregue el código siguiente al archivo:using Foundation; using System.Text; namespace PushNotificationsDemo.Platforms.iOS; 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(); } }
El código usará el método de extensión
ToHexString
que agregará que analiza el token de dispositivo recuperado.En Visual Studio, abra el archivo AppDelegate.csen la carpeta Platforms/iOS y agregue las siguientes instrucciones
using
:using System.Diagnostics; using Foundation; using PushNotificationsDemo.Platforms.iOS; using PushNotificationsDemo.Services; using UIKit; using UserNotifications;
En la clase
AppDelegate
, agregue campos de respaldo para almacenar referencias a las implementaciones deIPushDemoNotificationActionService
,INotificationRegistrationService
, yIDeviceInstallationService
:IPushDemoNotificationActionService _notificationActionService; INotificationRegistrationService _notificationRegistrationService; IDeviceInstallationService _deviceInstallationService;
En la clase
AppDelegate
, agregueNotificationActionService
,NotificationRegistrationService
, yDeviceInstallationService
propiedades privadas que recuperen sus implementaciones concretas del contenedor de inserción de dependencias de la aplicación:IPushDemoNotificationActionService NotificationActionService => _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>()); INotificationRegistrationService NotificationRegistrationService => _notificationRegistrationService ?? (_notificationRegistrationService = IPlatformApplication.Current.Services.GetService<INotificationRegistrationService>()); IDeviceInstallationService DeviceInstallationService => _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
En la clase
AppDelegate
, agregue el métodoCompleteRegistrationAsync
para establecer el valor de la propiedadIDeviceInstallationService.Token
:Task CompleteRegistrationAsync(NSData deviceToken) { DeviceInstallationService.Token = deviceToken.ToHexString(); return NotificationRegistrationService.RefreshRegistrationAsync(); }
Este método también actualiza el registro y almacena en caché el token de dispositivo si se ha actualizado desde que se almacenó por última vez.
En la clase
AppDelegate
, agregue el métodoProcessNotificationActions
para procesar los datos de notificación deNSDictionary
y llamar condicionalmente aNotificationActionService.TriggerAction
:void ProcessNotificationActions(NSDictionary userInfo) { if (userInfo == null) return; try { // If your app isn't in the foreground, the notification goes to Notification Center. // If your app is in the foreground, the notification goes directly to your app and you // need to process the notification payload yourself. 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); } }
En la clase
AppDelegate
, agregue el métodoRegisteredForRemoteNotifications
pasando el argumentodeviceToken
al métodoCompleteRegistrationAsync
:[Export("application:didRegisterForRemoteNotificationsWithDeviceToken:")] public void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken) { CompleteRegistrationAsync(deviceToken) .ContinueWith((task) => { if (task.IsFaulted) throw task.Exception; }); }
Se llamará a este método cuando se registre la aplicación para recibir una notificación remota y se use para solicitar el token de dispositivo único, que es efectivamente la dirección de la aplicación en el dispositivo.
En la clase
AppDelegate
, agregue el métodoReceivedRemoteNotification
pasando el argumentouserInfo
al métodoProcessNotificationActions
:[Export("application:didReceiveRemoteNotification:")] public void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo) { ProcessNotificationActions(userInfo); }
Se llamará a este método cuando la aplicación haya recibido una notificación remota y se use para procesar la notificación.
En la clase
AppDelegate
, agregue el métodoFailedToRegisterForRemoteNotifications
para registrar los errores:[Export("application:didFailToRegisterForRemoteNotificationsWithError:")] public void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error) { Debug.WriteLine(error.Description); }
Se llamará a este método cuando la aplicación no se haya registrado para recibir notificaciones remotas. Es posible que se produzca un error en el registro si el dispositivo no está conectado a la red, si el servidor APNS no es accesible o si la aplicación está configurada incorrectamente.
Nota:
En escenarios de producción, querrá implementar el registro y el control de errores adecuados en el método
FailedToRegisterForRemoteNotifications
.En la clase
AppDelegate
, agregue el métodoFinishedLaunching
para solicitar condicionalmente permiso para usar notificaciones y registrarse para las notificaciones remotas:[Export("application:didFinishLaunchingWithOptions:")] public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions) { if (DeviceInstallationService.NotificationsSupported) { UNUserNotificationCenter.Current.RequestAuthorization( UNAuthorizationOptions.Alert | UNAuthorizationOptions.Badge | UNAuthorizationOptions.Sound, (approvalGranted, error) => { if (approvalGranted && error == null) { MainThread.BeginInvokeOnMainThread(() => { UIApplication.SharedApplication.RegisterForRemoteNotifications(); }); } }); } using (var userInfo = launchOptions?.ObjectForKey(UIApplication.LaunchOptionsRemoteNotificationKey) as NSDictionary) { ProcessNotificationActions(userInfo); } return base.FinishedLaunching(application, launchOptions); }
Para obtener información acerca de cómo solicitar permiso para usar notificaciones, consulte Solicitar permiso para usar notificaciones en developer.apple.com.
Para obtener información acerca de las notificaciones en iOS, consulte Notificaciones de usuario en developer.apple.com.
Registro de tipos con el contenedor de inserción de dependencias de la aplicación
En Visual Studio, abra MauiProgram.cs y agregue una instrucción
using
para el espacio de nombresPushNotificationsDemo.Services
:using PushNotificationsDemo.Services;
En la clase
MauiProgram
, agregue código para el método de extensiónRegisterServices
que registra elDeviceInstallationService
en cada plataforma y los servicios dePushDemoNotificationActionService
yNotificationRegistrationService
multiplataforma, y que devuelve un objetoMauiAppBuilder
:public static MauiAppBuilder RegisterServices(this MauiAppBuilder builder) { #if IOS builder.Services.AddSingleton<IDeviceInstallationService, PushNotificationsDemo.Platforms.iOS.DeviceInstallationService>(); #elif ANDROID builder.Services.AddSingleton<IDeviceInstallationService, PushNotificationsDemo.Platforms.Android.DeviceInstallationService>(); #endif builder.Services.AddSingleton<IPushDemoNotificationActionService, PushDemoNotificationActionService>(); builder.Services.AddSingleton<INotificationRegistrationService>(new NotificationRegistrationService(Config.BackendServiceEndpoint, Config.ApiKey)); return builder; }
En la clase
MauiProgram
, agregue código para el método de extensiónRegisterViews
que registra el tipoMainPage
como singleton y que devuelve un objetoMauiAppBuilder
:public static MauiAppBuilder RegisterViews(this MauiAppBuilder builder) { builder.Services.AddSingleton<MainPage>(); return builder; }
El tipo
MainPage
se registra porque requiere una dependenciaINotificationRegistrationService
, y todos los tipos que requieran una dependencia deben registrarse con el contenedor de inserción de dependencias.En la clase
MauiProgram
, modifique el métodoCreateMauiApp
para que llame a los métodos de extensiónRegisterServices
yRegisterViews
:public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold"); }) .RegisterServices() .RegisterViews(); #if DEBUG builder.Logging.AddDebug(); #endif return builder.Build(); }
Para obtener más información sobre la inserción de dependencias en .NET MAUI, vea Inserción de dependencias.
Pruebas de la aplicación
Puede probar la aplicación mediante el envío de notificaciones de inserción a la aplicación mediante el servicio back-end o a través de Azure Portal.
El simulador de iOS admite notificaciones remotas en iOS 16+ cuando se ejecuta en macOS 13+ en equipos Mac con procesadores Apple Silicon o T2. Si no cumple estos requisitos de hardware, tendrá que probar la aplicación de iOS en un dispositivo físico. En Android, puede probar la aplicación en un dispositivo físico desbloqueado por el desarrollador o en un emulador.
Android e iOS muestran notificaciones de inserción en nombre de la aplicación cuando se ejecuta en segundo plano. Si la aplicación se ejecuta en primer plano cuando se recibe la notificación, el código de la aplicación determina el comportamiento. Por ejemplo, puede actualizar la interfaz de la aplicación para reflejar la nueva información contenida en la notificación.
Prueba mediante el servicio back-end
Para enviar una notificación de inserción de prueba a la aplicación a través del servicio back-end publicado en Azure App Service:
En Visual Studio, ejecute la aplicación PushNotificationsDemo en Android o iOS y seleccione el botón Registrar.
Nota:
Si está probando en Android, asegúrese de que no se está ejecutando con la configuración de depuración. Como alternativa, si la aplicación se ha implementado anteriormente, asegúrese de que se ha cerrado la fuerza y a continuación, vuelva a iniciarla desde el iniciador.
En las herramientas REST que prefiera, envíe una
POST
solicitud a la siguiente dirección:https://<app_name>.azurewebsites.net/api/notifications/requests
Asegúrese de configurar los encabezados de solicitud para incluir la clave
apikey
y su valor, establecer el cuerpo en sin procesar y usar el siguiente contenido JSON:{ "text": "Message from REST tooling!", "action": "action_a" }
La solicitud general debe ser similar al ejemplo siguiente:
POST /api/notifications/requests HTTP/1.1 Host: https://<app_name>.azurewebsites.net apikey: <your_api_key> Content-Type: application/json { "text": "Message from REST tooling!", "action": "action_a" }
En las herramientas REST que prefiera, valide que recibe una respuesta 200 OK.
En la aplicación en Android o iOS, debería aparecer una alerta que muestra la Acción ActionA recibida.
Para obtener más información acerca de cómo llamar a las API de REST, consulte Uso de archivos .http en Visual Studio y Probar API web con Http Repl. En Visual Studio Code, Cliente REST se puede usar para probar las API de REST.
Prueba mediante Azure Portal
Azure Notification Hubs le permite comprobar que la aplicación puede recibir notificaciones de inserción.
Para enviar una notificación de inserción de prueba a la aplicación a través de Azure Portal:
En Visual Studio, ejecute la aplicación PushNotificationsDemo en Android o iOS y seleccione el botón Registrar.
Nota:
Si está probando en Android, asegúrese de que no se está ejecutando con la configuración de depuración. Como alternativa, si la aplicación se ha implementado anteriormente, asegúrese de que se ha cerrado la fuerza y a continuación, vuelva a iniciarla desde el iniciador.
En Azure Portal, vaya al centro de notificaciones y seleccione el botón Enviar prueba en la hoja Información general.
En la hoja Enviar prueba, seleccione la Plataforma necesaria y modifique la carga.
Para Apple, use la siguiente carga:
{ "aps": { "alert": "Message from Notification Hub!" }, "action": "action_a" }
Para Android, use la siguiente carga:
{ "message": { "notification": { "title": "PushDemo", "body": "Message from Notification Hub!" }, "data": { "action": "action_a" } } }
Azure Portal debe indicar que la notificación se ha enviado correctamente.
Para obtener información acerca del formato de mensaje Firebase Cloud Messaging, consulte Acerca de los mensajes de FCM en developer.android.com.
En la aplicación en Android o iOS, debería aparecer una alerta que muestra la Acción ActionA recibida.
Solución de problemas
En las secciones siguientes se describen los problemas comunes detectados al intentar consumir notificaciones de inserción en una aplicación cliente.
No hay respuesta del servicio de back-end
Cuando realice pruebas localmente, asegúrese de que el servicio de back-end se esté ejecutando y de que esté usando el puerto correcto.
Si realiza pruebas en la aplicación de API de Azure, compruebe que el servicio se está ejecutando y que se ha implementado y se ha iniciado sin errores.
Asegúrese de que ha especificado correctamente la dirección base en las herramientas REST o en la configuración de la aplicación MAUI de .NET. La dirección base debe ser https://<api_name>.azurewebsites.net
o https://localhost:7020
al probar localmente.
Se recibe un código de estado 401 del servicio de back-end
Compruebe que está configurando correctamente el encabezado de la solicitud apikey
y que este valor coincide con el que configuró para el servicio back-end.
Si recibe este error al probar localmente, asegúrese de que el valor de clave que definió en la aplicación MAUI de .NET coincide con el Authentication:ApiKey
valor de secretos de usuario usado por el servicio back-end.
Si está probando con una aplicación de API de Azure, asegúrese de que el valor de clave definido en la aplicación MAUI de .NET coincide con el valor de configuración de la aplicación Authentication:ApiKey
definido en Azure Portal. Si ha creado o cambiado esta configuración de aplicación después de haber implementado el servicio back-end, debe reiniciar el servicio para que el valor surta efecto.
Se recibe un código de estado 404 del servicio de back-end
Compruebe que el punto de conexión y el método de solicitud HTTP son correctos:
- PUT -
https://<api_name>.azurewebsites.net/api/notifications/installations
- DELETE:
https://<api_name>.azurewebsites.net/api/notifications/installations/<installation_id>
- POST:
https://<api_name>.azurewebsites.net/api/notifications/requests
O cuando se realizan las pruebas de manera local:
- PUT:
https://localhost:7020/api/notifications/installations
- DELETE:
https://localhost:7020/api/notifications/installations/<installation_id>
- POST:
https://localhost:7020/api/notifications/requests
Importante
Al especificar la dirección base en la aplicación MAUI de .NET, asegúrese de que finaliza con un /
. La dirección base debe ser https://<api_name>.azurewebsites.net
o https://localhost:7020/
al probar localmente.
No se reciben notificaciones en Android después de iniciar o detener una sesión de depuración
Asegúrese de registrar cada vez que inicie una sesión de depuración. El depurador hará que se genere un nuevo token de Firebase y por tanto, se debe actualizar la instalación del centro de notificaciones.
No se puede realizar el registro y aparece un mensaje de error del centro de notificaciones
Compruebe que el dispositivo de prueba tenga conectividad de red. A continuación, determine el código de estado de respuesta HTTP estableciendo un punto de interrupción para inspeccionar la propiedad StatusCode
en HttpResponse
.
Revise las sugerencias de solución de problemas anteriores, si procede, en función del código de estado.
Establezca un punto de interrupción en las líneas que devuelven códigos de estado específicos para la API correspondiente. Después, intente llamar al servicio de back-end al depurar localmente.
Valide que el servicio back-end funciona según lo previsto por las herramientas REST que prefiera y use la carga creada por la aplicación MAUI de .NET para la plataforma elegida.
Revise las secciones de configuración específicas de la plataforma para asegurarse de que no se ha omitido ningún paso. Compruebe que los valores adecuados se resuelven para las variables InstallationId
y Token
para la plataforma elegida.
No se puede resolver un identificador para el dispositivo, el mensaje de error del dispositivo
Revise las secciones de configuración específicas de la plataforma para asegurarse de que no se ha omitido ningún paso.