Partager via


Tutoriel : Envoyer des notifications Push aux applications .NET MAUI à l’aide d’Azure Notification Hubs via un service back-end

Parcourez l’exemple. Parcourir l'exemple

Les notifications Push fournissent des informations d’un système principal à une application cliente. Apple, Google et d’autres plateformes ont chacun leur propre service de notification Push (PNS). Azure Notification Hubs vous permet de centraliser les notifications entre plateformes afin que votre application back-end puisse communiquer avec un seul hub, qui s’occupe de distribuer des notifications à chaque PNS.

Azure Notification Hubs exige que les applications s’inscrivent auprès du hub et définissent éventuellement des modèles et/ou s’abonnent à des balises :

  • L’exécution d’une installation d’appareil lie un handle PNS à un identificateur dans Azure Notification Hub. Pour plus d’informations sur les inscriptions, consultez gestion des inscriptions.
  • Les modèles permettent aux appareils de spécifier des modèles de messages paramétrables. Les messages entrants peuvent être personnalisés par appareil. Pour plus d’informations, consultez modèles Notification Hubs.
  • Les balises peuvent être utilisées pour s’abonner à des catégories de messages telles que les actualités, les sports et les conditions météorologiques. Pour plus d’informations, voir Routage et expressions de balise.

Dans ce tutoriel, vous allez utiliser Azure Notification Hubs pour envoyer des notifications Push à une application d’interface utilisateur d’application multiplateforme .NET (.NET MAUI) ciblant Android et iOS. Un backend ASP.NET Core Web API est utilisé pour gérer l'enregistrement de l'appareil pour le client et pour lancer une notification push. Ces opérations sont gérées à l’aide du package NuGet Microsoft.Azure.NotificationHubs. Pour plus d’informations sur l’approche globale, consultez gestion de l’inscription à partir d’un serveur principal.

Dans ce tutoriel, vous allez :

  • Configurer les services de notification Push et Azure Notification Hub.
  • Créez une application principale WebAPI ASP.NET Core.
  • Créer une application .NET MAUI.
  • Configurez l’application Android pour les notifications Push.
  • Configurez l’application iOS pour les notifications Push.
  • Tester l'application.
  • Résolvez les problèmes d’installation et de configuration.

Prérequis

Pour suivre ce tutoriel, vous aurez besoin des points suivants :

  • Un compte Azure avec un abonnement actif.
  • Pc ou Mac exécutant la dernière version de Visual Studio/Visual Studio Code avec la charge de travail de développement de l’interface utilisateur de l’application multiplateforme .NET et les charges de travail de développement web et ASP.NET et web installées.

Pour Android, vous devez disposer des éléments suivants :

  • Un appareil physique déverrouillé par un développeur ou un émulateur exécutant l’API 26+ avec Google Play Services installé.

Pour iOS, vous devez disposer des éléments suivants :

  • Un compte de développeur Apple actif.
  • Un Mac exécutant Xcode, ainsi qu’un certificat de développeur valide installé dans votre trousseau

Ensuite, sur iOS, vous devez avoir :

  • Simulateur iOS 16+ qui s’exécute dans macOS 13+ sur les ordinateurs Mac avec des processeurs Apple Silicon ou T2.

    OR

  • Un appareil iOS physique inscrit à votre compte de développeur (exécutant iOS 13.0+).

  • Votre appareil physique inscrit dans votre compte de développeur Apple et associé à votre certificat.

Important

Le simulateur iOS prend en charge les notifications à distance dans iOS 16+ lors de l’exécution dans macOS 13+ sur les ordinateurs Mac avec des processeurs Apple Silicon ou T2. Si vous ne répondez pas à ces exigences matérielles, vous aurez besoin d’un compte de développeur Apple actif et d’un appareil physique.

Pour suivre ce tutoriel, vous devez connaître les connaissances suivantes :

Bien que ce didacticiel cible Visual Studio, il est possible de le suivre à l’aide de Visual Studio Code sur un PC ou un Mac. Toutefois, il y aura des différences qui nécessitent une réconciliation. Par exemple, les descriptions de l’interface utilisateur et des flux de travail, des noms de modèles et de la configuration de l’environnement.

Configurer les services de notification Push et Azure Notification Hub

Dans cette section, vous allez configurer Firebase Cloud Messaging et Apple Push Notification Services (APNS). Vous allez ensuite créer et configurer un Azure Notification Hub pour travailler avec ces services.

Créer un projet Firebase

Pour créer un projet Firebase :

  1. Dans un navigateur web, connectez-vous à la console Firebase.

  2. Dans la console Firebase, sélectionnez le bouton Ajouter un projet et créez un projet Firebase, en entrant PushDemo en tant que nom de projet.

    Remarque

    Un nom unique sera généré pour vous. Par défaut, cela comprend une variante minuscule du nom que vous avez fourni, ainsi qu’un nombre généré séparé par un tiret. Vous pouvez le modifier si vous le souhaitez, à condition que vos modifications soient toujours globalement uniques.

  3. Une fois votre projet créé, sélectionnez le logo Android pour ajouter Firebase à une application Android :

    Capture d’écran de l’ajout de Firebase à une application Android dans la console Firebase Cloud Messaging.

  4. Dans la page Ajouter Firebase à votre application Android, entrez un nom pour votre package, éventuellement un surnom d’application, puis sélectionnez le bouton Inscrire l’application :

    Capture d’écran de l’inscription de votre application Android avec Firebase.

  5. Dans la page Ajouter Firebase à votre application Android, sélectionnez le bouton Télécharger google-services.json et enregistrez le fichier dans un dossier local avant de sélectionner le bouton Suivant :

    Capture d’écran du téléchargement du fichier JSON des services Google.

  6. Dans la page Ajouter Firebase à votre application Android, sélectionnez le bouton Suivant.

  7. Dans la page Ajouter Firebase à votre application Android, sélectionnez le bouton Continuer vers la console.

  8. Dans la console Firebase, sélectionnez l’icône Vue d’ensemble du projet, puis sélectionnez Paramètres du projet :

    Capture d’écran de la sélection des paramètres du projet dans la console Firebase Cloud Messaging.

  9. Dans les paramètres du projet, sélectionnez l’onglet Cloud Messaging. Vous verrez que API Firebase Cloud Messaging (V1) est activée :

    Capture d’écran montrant que Firebase Cloud Messaging V1 est activé.

  10. Dans les paramètres du projet, sélectionnez l’onglet Comptes de service, puis sélectionnez le bouton Générer une nouvelle clé privée.

  11. Dans la boîte de dialogue Générer une nouvelle clé privée, sélectionnez le bouton Générer la clé :

    Capture d’écran de la génération d’une nouvelle clé privée dans la console Firebase Cloud Messaging.

    Un fichier JSON sera téléchargé, qui contiendra des valeurs que vous entrez dans votre hub de notification Azure.

Inscrire votre application iOS pour les notifications Push

Pour envoyer des notifications Push à une application iOS, vous devez inscrire votre application auprès d’Apple et vous inscrire aux notifications Push. Pour ce faire, procédez comme suit dans la documentation Azure Notification Hub suivante :

Si vous souhaitez recevoir des notifications Push sur un appareil physique, vous devez également créer un profil d’approvisionnement.

Important

Pour recevoir des notifications en arrière-plan sur iOS, vous devez ajouter le mode en arrière-plan des notifications à distance à votre application. Pour plus d’informations, consultez Activer la fonctionnalité de notifications à distance sur developer.apple.com.

Créer un Hub de notification Azure

Pour créer un hub de notification dans le portail Azure :

  1. Dans un navigateur web, connectez-vous au portail Azure.
  2. Dans le portail Azure, cliquez sur le bouton Créer une ressource, puis recherchez et choisissez Notification Hub avant de sélectionner le bouton Créer.
  3. Dans la page Notification Hub, procédez comme suit :
    1. Dans le champ abonnement, sélectionnez le nom de l’abonnement Azure que vous souhaitez utiliser, puis sélectionnez un groupe de ressources existant ou créez-en un.

    2. Dans le champ Détails de l’espace de noms, entrez un nom unique pour le nouvel espace de noms.

    3. Dans le champ Détails du hub de notification, tapez un nom pour le hub de notification. Cela est nécessaire, car un espace de noms contient un ou plusieurs hubs de notification.

    4. Dans la liste déroulante Emplacement, sélectionnez une valeur qui spécifie l’emplacement dans lequel vous souhaitez créer le hub de notification.

    5. Examinez l’option Zones de disponibilité. Si vous avez choisi une région qui a des zones de disponibilité, la case à cocher est cochée par défaut.

      Remarque

      Les zones de disponibilité étant une fonctionnalité payante, des frais supplémentaires sont ajoutés à votre niveau.

    6. Choisissez une option récupération d’urgence : aucune, région de récupération jumelée ou région de récupération flexible. Si vous choisissez Région de récupération jumelée, la région de basculement s’affiche. Si vous sélectionnez Région de récupération flexible, utilisez la liste déroulante pour choisir parmi une liste de régions de récupération.

    7. Cliquez sur le bouton Créer. Le hub de notification est créé.

  4. Dans le portail Azure, accédez à votre hub de notification nouvellement créé, puis accédez au panneau Gérer> les stratégies d’accès.
  5. Dans le volet Stratégies d’accès, notez la chaîne de connexion de la stratégie DefaultFullSharedAccessSignature. Vous en aurez besoin ultérieurement lors de la création d’un service principal qui communique avec votre hub de notification.

Pour plus d’informations sur la création d’un hub de notification, consultez Créer un hub de notification Azure dans le portail Azure.

Configurer Firebase Cloud Messaging dans le hub de notification

Pour configurer votre hub de notification pour communiquer avec Firebase Cloud Messaging :

  1. Dans le portail Azure, accédez à votre hub de notification et sélectionnez le panneau Paramètres> Google (FCM v1).

  2. Dans le volet Google (FCM v1), entrez les valeurs des champs de clé privée, de messagerie cliente et de ID du projet. Ces valeurs sont disponibles dans le fichier JSON de clé privée que vous avez téléchargé à partir de Firebase Cloud Messaging :

    Champ Azure Clé JSON Exemple de valeur JSON
    Clé privée private_key Cette valeur doit commencer par -----BEGIN PRIVATE KEY-----\n et se terminer par -----END PRIVATE KEY-----\n.
    Adresse e-mail du client client_email firebase-adminsdk-55sfg@pushdemo-d6ab2.iam.gserviceaccount.com
    ID Projet project_id pushdemo-d6ab2
  3. Dans le panneau Google (FCM v1), sélectionnez le bouton Enregistrer.

Configurer le service de notification Push Apple dans le hub de notification

Dans le portail Azure, accédez à votre hub de notification et sélectionnez le panneau paramètres> Apple (APNS). Suivez ensuite les étapes appropriées en fonction de l’approche que vous avez choisie précédemment lors de la création d’un certificat pour le hub de notification.

Important

Lorsque vous définissez le mode application, choisissez uniquement Production si vous souhaitez envoyer des notifications Push aux utilisateurs qui ont acheté votre application à partir du Store.

Option 1 - Utiliser un certificat Push .p12

  1. Dans le panneau Apple (APNS), sélectionnez le mode d’authentification certificat.
  2. Dans le panneau Apple (APNS), sélectionnez l’icône de fichier en regard du champ Charger le certificat. Sélectionnez ensuite le fichier .p12 que vous avez exporté précédemment et chargez-le.
  3. Dans le panneau Apple (APNS), entrez le mot de passe du certificat dans le champ Mot de passe si nécessaire.
  4. Dans le panneau Apple (APNS), sélectionnez le mode d’application bac à sable (Sandbox).
  5. Dans le panneau Apple (APNS), sélectionnez le bouton Enregistrer.

Option 2 - Utiliser l’authentification basée sur les jetons

  1. Dans le panneau Apple (APNS), sélectionnez le mode d’authentification jeton.
  2. Dans le panneau Apple (APNS), entrez les valeurs que vous avez acquises précédemment pour Key Id, Bundle Id, Team Idet les champs jeton.
  3. Dans le panneau Apple (APNS), sélectionnez le mode d’application bac à sable (Sandbox).
  4. Dans le panneau Apple (APNS), sélectionnez le bouton Enregistrer.

Créer une application back-end d’API web core ASP.NET

Dans cette section, vous allez créer un serveur principal d’API web core ASP.NET pour gérer installation de l’appareil et envoyer des notifications à l’application MAUI .NET.

Créer un projet d’API web

Pour créer un projet d’API web :

  1. Dans Visual Studio, créez un projet d’API web ASP.NET Core :

    Capture d’écran de la création d’un projet d’API web core ASP.NET dans Visual Studio.

  2. Dans la boîte de dialogue Configurer votre nouveau projet, nommez le projet PushNotificationsAPI.

  3. Dans la boîte de dialogue informations supplémentaires, vérifiez que les cases Configurer pour HTTPS et Utiliser des contrôleurs sont activées :

    Capture d’écran de la configuration du projet d’API web core ASP.NET dans Visual Studio.

  4. Une fois le projet créé, appuyez sur F5 pour exécuter le projet.

    L’application est actuellement configurée pour utiliser le WeatherForecastController comme launchUrl, qui est définie dans le fichier Properties\launchSettings.json. L’application se lance dans un navigateur web et affiche des données JSON.

    Important

    Lorsque vous exécutez un projet ASP.NET Core qui utilise HTTPS, Visual Studio détecte si le certificat de développement HTTPS ASP.NET Core est installé dans votre magasin de certificats utilisateur local, et propose de l’installer et de l’approuver s’il est manquant.

  5. Fermez le navigateur web.

  6. Dans Explorateur de solutions, développez le dossier contrôleurs et supprimez WeatherForecastController.cs.

  7. Dans Explorateur de solutions, à la racine du projet, supprimez WeatherForecast.cs.

  8. Ouvrez une fenêtre de commande et accédez au répertoire qui contient le fichier projet. Exécutez ensuite les commandes suivantes :

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

    Remplacez les valeurs d’espace réservé par votre propre nom Azure Notification Hub et vos propres valeurs de chaîne de connexion. Vous trouverez ces informations à l’emplacement suivant dans votre hub de notification Azure :

    Valeur de configuration Emplacement
    NotificationHub:Name Consultez Nom dans le résumé Essentials en haut de la page Vue d’ensemble.
    NotificationHub:ConnectinString Consultez DefaultFullSharedAccessSignature* dans la page Stratégies d’accès.

    Cette opération configure les valeurs de configuration locales à l’aide de l’outil Secret Manager. Cela dissocie vos secrets Azure Notification Hub de la solution Visual Studio pour vous assurer qu’ils ne se retrouvent pas dans le contrôle de code source.

    Conseil

    Pour les scénarios de production, envisagez un service tel que Azure KeyVault pour stocker en toute sécurité la chaîne de connexion.

Authentifier des clients avec une clé API

Pour authentifier les clients avec une clé API :

  1. Ouvrez une fenêtre de commande et accédez au répertoire qui contient le fichier projet. Exécutez ensuite les commandes suivantes :

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

    Remplacez la valeur d’espace réservé par votre clé API, qui peut être n’importe quelle valeur.

  2. Dans Visual Studio, ajoutez un nouveau dossier nommé Authentication à votre projet, puis ajoutez une nouvelle classe nommée ApiKeyAuthOptions au dossier Authentication et remplacez son code par le code suivant :

    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; }
    }
    
  3. Dans Visual Studio, ajoutez une nouvelle classe nommée ApiKeyAuthHandler au dossier Authentication et remplacez son code par le code suivant :

    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 gestionnaire d’authentification est un type qui implémente le comportement d’un schéma, qui, dans ce cas, est un schéma de clé API personnalisé.

  4. Dans Visual Studio, ajoutez une nouvelle classe nommée AuthenticationBuilderExtensions au dossier Authentication et remplacez son code par le code suivant :

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

    Cette méthode d’extension sera utilisée pour simplifier le code de configuration du intergiciel dans Program.cs.

  5. Dans Visual Studio, ouvrez Program.cs et mettez à jour le code pour configurer l’authentification par clé API sous l’appel à la méthode 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);
    
  6. Dans Program.cs, mettez à jour le code sous le commentaire // Configure the HTTP request pipeline pour appeler les méthodes d’extension UseRouting, UseAuthenticationet MapControllers :

    // Configure the HTTP request pipeline.
    
    app.UseHttpsRedirection();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.MapControllers();
    
    app.Run();
    

    La méthode d’extension UseAuthentication inscrit le middleware qui utilise le schéma d’authentification précédemment inscrit. UseAuthentication doit être appelée avant tout intergiciel qui dépend de l’authentification des utilisateurs.

    Remarque

    Bien qu’une clé API ne soit pas aussi sécurisée qu’un jeton, elle suffit pour ce didacticiel et sera facilement configurée via le middleware ASP.NET.

Ajouter et configurer des services

Pour ajouter et configurer des services dans votre application back-end d’API web :

  1. Dans Visual Studio, ajoutez le Microsoft.Azure.NotificationHubs package NuGet à votre projet. Ce package NuGet est utilisé pour accéder à votre hub de notification, encapsulé dans un service.

  2. Dans Visual Studio, ajoutez un nouveau dossier nommé Models à votre projet, puis ajoutez une nouvelle classe nommée PushTemplates au dossier Models et remplacez son code par le code suivant :

    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 classe PushTemplates contient des charges utiles de notification tokenisées pour les notifications Push génériques et silencieuses. Ces charges utiles sont définies en dehors de l’installation pour permettre l’expérimentation sans avoir à mettre à jour les installations existantes via le service. La gestion des modifications apportées aux installations de cette façon n’est pas autorisée pour cet article. Dans les scénarios de produit, envisagez d’utiliser modèles personnalisés.

  3. Dans Visual Studio, ajoutez une nouvelle classe nommée DeviceInstallation au dossier Models et remplacez son code par le code suivant :

    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>();
    }
    
  4. Dans Visual Studio, ajoutez une nouvelle classe nommée NotificationRequest au dossier Models et remplacez son code par le code suivant :

    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; }
    }
    
  5. Dans Visual Studio, ajoutez une nouvelle classe nommée NotificationHubOptions au dossier Models et remplacez son code par le code suivant :

    using System.ComponentModel.DataAnnotations;
    
    namespace PushNotificationsAPI.Models;
    
    public class NotificationHubOptions
    {
        [Required]
        public string Name { get; set; }
    
        [Required]
        public string ConnectionString { get; set; }
    }
    
  6. Dans Visual Studio, ajoutez un nouveau dossier nommé Services à votre projet, puis ajoutez une nouvelle interface nommée INotificationService au dossier services et remplacez son code par le code suivant :

    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);
    }
    
  7. Dans Visual Studio, ajoutez une nouvelle classe nommée NotificationHubService au dossier Services et remplacez son code par le code suivant :

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

    L’expression de balise fournie à la méthode SendTemplateNotificationsAsync est limitée à 20 balises s’ils contiennent uniquement des ORs. Sinon, ils sont limités à 6 balises. Pour plus d’informations, consultez Routage et expressions de balises.

  8. Dans Visual Studio, ouvrez Program.cs et mettez à jour le code pour ajouter le NotificationHubService en tant qu’implémentation singleton de INotificationService sous l’appel à la méthode builder.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();
    

Créer l’API REST de notifications

Pour créer l’API REST de notifications :

  1. Dans Visual Studio, ajoutez un nouveau contrôleur nommé NotificationsController au dossier Controllers.

    Conseil

    Choisissez le modèle de contrôleur d’API avec des actions en lecture/écriture.

  2. Dans le fichier NotificationsController.cs, ajoutez les instructions using suivantes en haut du fichier :

    using System.ComponentModel.DataAnnotations;
    using System.Net;
    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.Mvc;
    using PushNotificationsAPI.Models;
    using PushNotificationsAPI.Services;
    
  3. Dans le fichier NotificationsController.cs, ajoutez l’attribut Authorize à la classe NotificationsController :

    [Authorize]
    [ApiController]
    [Route("api/[controller]")]
    public class NotificationsController : ControllerBase
    
  4. Dans le fichier NotificationsController.cs, mettez à jour le constructeur NotificationsContoller pour accepter l’instance inscrite de INotificationService en tant qu’argument, puis affectez-le à un membre en lecture seule :

    readonly INotificationService _notificationService;
    
    public NotificationsController(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }
    
  5. Dans le fichier NotificationsContoller.cs, remplacez toutes les méthodes par le code suivant :

    [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();
    }
    
  6. Dans le fichier propriétés/launchSettings.json, remplacez la propriété launchUrl pour chaque profil de weatherforecast par api/notifications.

Créer une application API

Vous allez maintenant créer une application API dans Azure App Service pour héberger votre service principal. Vous pouvez effectuer cette opération directement à partir de Visual Studio ou de Visual Studio Code, avec Azure CLI, Azure PowerShell, Azure Developer CLI et via le portail Azure. Pour plus d’informations, consultez Publier votre application web.

Pour créer une application API dans le portail Azure :

  1. Dans un navigateur web, connectez-vous au portail Azure.

  2. Dans le portail Azure, cliquez sur le bouton Créer une ressource, puis recherchez et choisissez application API avant de sélectionner le bouton Créer.

  3. Dans la page Créer une application API, mettez à jour les champs suivants avant de sélectionner le bouton Créer :

    Champ Action
    Abonnement Choisissez le même abonnement cible dans lequel vous avez créé le hub de notification.
    Groupe de ressources Choisissez le même groupe de ressources dans lequel vous avez créé le hub de notification.
    Nom Entrez un nom globalement unique.
    Pile d’exécution Vérifiez que la dernière version de .NET est sélectionnée.
  4. Une fois que l’application API a été configurée, accédez à la ressource.

  5. Dans la page Vue d’ensemble, notez la valeur de domaine par défaut. Cette URL est votre point de terminaison principal qui sera consommé à partir de votre application .NET MAUI. L’URL utilise le nom de l’application API que vous avez spécifié, avec le format https://<app_name>.azurewebsites.net.

  6. Dans le portail Azure, accédez au panneau Paramètres> Environnement variables, puis vérifiez que l’onglet paramètres de l’application est sélectionné. Utilisez ensuite le bouton Ajouter pour ajouter les paramètres suivants :

    Nom Valeur
    Authentication:ApiKey <api_key_value>
    NotificationHub:Name <hub_name_value>
    NotificationHub:ConnectionString <hub_connection_string_value>

    Important

    Le paramètre d’application Authentication:ApiKey a été ajouté par souci de simplicité. Pour les scénarios de production, envisagez un service tel que Azure KeyVault pour stocker en toute sécurité la chaîne de connexion.

    Une fois que tous ces paramètres ont été entrés, sélectionnez le bouton Appliquer, puis le bouton Confirmer.

Publier le service back-end

Pour publier votre service principal sur Azure App Service :

  1. Dans Visual Studio, cliquez avec le bouton droit sur votre projet, puis sélectionnez Publier.
  2. Dans l’Assistant Publier, sélectionnez Azure, puis le bouton Suivant.
  3. Dans l’Assistant Publier, sélectionnez Azure App Service (Windows), puis le bouton Suivant.
  4. Dans l’Assistant Publier, suivez le flux d’authentification pour connecter Visual Studio à votre abonnement Azure et publier l’application.

Visual Studio génère, packages et publie l’application sur Azure, puis lance l’application dans votre navigateur par défaut. Pour plus d’informations, consultez Publier une application web ASP.NET.

Conseil

Vous pouvez télécharger un profil de publication pour votre application à partir du panneau vue d’ensemble de votre application API dans le portail Azure, puis utiliser le profil dans Visual Studio pour publier votre application.

Valider l’API publiée

Pour vérifier que l’application API a été publiée correctement, vous devez utiliser l’outil REST de votre choix pour envoyer une demande de POST à l’adresse suivante :

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

Remarque

L’adresse de base est https://<app_name>.azurewebsites.net.

Vérifiez que vous configurez les en-têtes de requête pour inclure la clé apikey et sa valeur, définissez le corps sur brut et utilisez le contenu JSON de l’espace réservé suivant :

{}

Vous devez recevoir une réponse 400 Bad Request du service.

Remarque

Il n’est pas encore possible de tester l’API à l’aide de données de requête valides, car cela nécessite des informations spécifiques à la plateforme à partir de l’application .NET MAUI.

Pour plus d’informations sur l’appel d’API REST, consultez Utiliser des fichiers .http dans Visual Studio et Tester des API web avec le Http Repl. Dans Visual Studio Code, client REST peut être utilisé pour tester les API REST.

Créer une application .NET MAUI

Dans cette section, vous allez créer une application d’interface utilisateur d’application multiplateforme .NET (.NET MAUI) qui vous permet de vous inscrire pour recevoir des notifications Push à partir d’un hub de notification via le service back-end et désinscrire.

Pour créer votre application .NET MAUI :

  1. Dans Visual Studio, créez une application .NET MAUI nommée PushNotificationsDemo, à l’aide du modèle de projet application MAUI .NET.

  2. Dans Visual Studio, ajoutez un nouveau dossier nommé Models au projet .NET MAUI, puis ajoutez une nouvelle classe nommée DeviceInstallation au dossier Models et remplacez son code par le code suivant :

    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>();
    }
    
  3. Dans Visual Studio, ajoutez une énumération nommée PushDemoAction au dossier Models et remplacez son code par le code suivant :

    namespace PushNotificationsDemo.Models;
    
    public enum PushDemoAction
    {
        ActionA,
        ActionB
    }
    
  4. Dans Visual Studio, ajoutez un nouveau dossier nommé Services au projet .NET MAUI, puis ajoutez une nouvelle interface nommée IDeviceInstallationService au dossier Services et remplacez son code par le code suivant :

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

    Cette interface sera implémentée ultérieurement sur chaque plateforme pour fournir les informations DeviceInstallation requises par le service principal.

  5. Dans Visual Studio, ajoutez une interface nommée INotificationRegistrationService au dossier Services et remplacez son code par le code suivant :

    namespace PushNotificationsDemo.Services;
    
    public interface INotificationRegistrationService
    {
        Task DeregisterDeviceAsync();
        Task RegisterDeviceAsync(params string[] tags);
        Task RefreshRegistrationAsync();
    }
    

    Cette interface gère l’interaction entre le client et le service principal.

  6. Dans Visual Studio, ajoutez une interface nommée INotificationActionService au dossier Services et remplacez son code par le code suivant :

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

    Cette interface sera utilisée comme mécanisme simple pour centraliser la gestion des actions de notification.

  7. Dans Visual Studio, ajoutez une interface nommée IPushDemoNotificationActionService au dossier Services et remplacez son code par le code suivant :

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

    Le type IPushDemoNotificationActionService est spécifique à cette application et utilise l’énumération PushDemoAction pour identifier l’action déclenchée à l’aide d’une approche fortement typée.

  8. Dans Visual Studio, ajoutez une classe nommée NotificationRegistrationService au dossier Services et remplacez son code par le code suivant :

    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.Windows[0].Page.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();
        }
    }
    
  9. Dans Visual Studio, ajoutez une classe nommée PushDemoNotificationActionService au dossier Services et remplacez son code par le code suivant :

    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);
        }
    }
    
  10. Dans Visual Studio, ajoutez une classe nommée Config à la racine du projet et remplacez son code par le code suivant :

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

    La classe Config est utilisée comme moyen simple de garder vos secrets hors contrôle de code source. Vous pouvez remplacer ces valeurs dans le cadre d’une génération automatisée ou les remplacer à l’aide d’une classe partielle locale.

    Important

    Lorsque vous spécifiez l’adresse de base dans l’application .NET MAUI, vérifiez qu’elle se termine par un /.

  11. Dans Visual Studio, ajoutez une classe nommée Config.local_secrets à la racine du projet. Remplacez ensuite le code dans le fichier Config.local_secrets.cs par le code suivant :

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

    Remplacez les valeurs d’espace réservé par les valeurs que vous avez choisies lors de la création du service principal. L’URL BackendServiceEndpoint doit utiliser le format https://<api_app_name>.azurewebsites.net/.

    Conseil

    N’oubliez pas d’ajouter *.local_secrets.* à votre fichier .gitignore pour éviter de valider ce fichier dans le contrôle de code source.

Créer l’interface utilisateur

Pour créer l’interface utilisateur de l’application :

  1. Dans Visual Studio, ouvrez MainPage.xaml et remplacez le VerticalStackLayout et ses enfants par le code XAML suivant :

    <VerticalStackLayout Margin="20"
                         Spacing="6">
        <Button x:Name="registerButton"
                Text="Register"
                Clicked="OnRegisterButtonClicked" />
        <Button x:Name="deregisterButton"
                Text="Deregister"
                Clicked="OnDeregisterButtonClicked" />
    </VerticalStackLayout>
    
  2. Dans Visual Studio, ouvrez MainPage.xaml.cs et ajoutez une instruction using pour l’espace de noms PushNotificationsDemo.Services :

    using PushNotificationsDemo.Services;
    
  3. Dans MainPage.xaml.cs, ajoutez un champ de stockage readonly pour stocker une référence à l’implémentation INotificationRegistrationService :

    readonly INotificationRegistrationService _notificationRegistrationService;
    
  4. Dans le constructeur MainPage, résolvez l’implémentation INotificationRegistrationService et affectez-la au champ de stockage _notificationRegistrationService :

    public MainPage(INotificationRegistrationService service)
    {
        InitializeComponent();
    
        _notificationRegistrationService = service;
    }
    
  5. Dans la classe MainPage, implémentez les gestionnaires d’événements OnRegisterButtonClicked et OnDeregisterButtonClicked, en appelant les méthodes d’inscription et de désinscription correspondantes sur l’objet INotificationRegistrationService :

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

    Important

    Dans l’application, l’inscription et la désinscription sont effectuées en réponse à l’entrée de l’utilisateur, pour permettre à cette fonctionnalité d’être explorée et testée plus facilement. Dans une application de production, vous effectuez généralement les actions d’inscription et de désinscription pendant le point approprié dans le cycle de vie de l’application, sans nécessiter d’entrée explicite de l’utilisateur.

  6. Dans Visual Studio, ouvrez App.xaml.cs et ajoutez les instructions suivantes using :

    using PushNotificationsDemo.Models;
    using PushNotificationsDemo.Services;
    
  7. Dans App.xaml.cs, ajoutez un champ de stockage readonly pour stocker une référence à l’implémentation IPushDemoNotificationActionService :

    readonly IPushDemoNotificationActionService _actionService;
    
  1. Dans le constructeur App, résolvez l’implémentation IPushDemoNotificationActionService et affectez-la au champ de stockage _actionService , puis abonnez-vous à l’événement IPushDemoNotificationActionService.ActionTriggered :

    public App(IPushDemoNotificationActionService service)
    {
        InitializeComponent();
    
        _actionService = service;
        _actionService.ActionTriggered += NotificationActionTriggered;
    
        MainPage = new AppShell();
    }
    
  1. Dans le constructeur App, résolvez l’implémentation IPushDemoNotificationActionService et affectez-la au champ de stockage _actionService , puis abonnez-vous à l’événement IPushDemoNotificationActionService.ActionTriggered :

    public App(IPushDemoNotificationActionService service)
    {
        InitializeComponent();
    
        _actionService = service;
        _actionService.ActionTriggered += NotificationActionTriggered;
    }
    
  1. Dans la classe App, implémentez le gestionnaire d’événements pour l’événement IPushDemoNotificationActionService.ActionTriggered :

    void NotificationActionTriggered(object sender, PushDemoAction e)
    {
        ShowActionAlert(e);
    }
    
    void ShowActionAlert(PushDemoAction action)
    {
        MainThread.BeginInvokeOnMainThread(() =>
        {
            Windows[0].Page?.DisplayAlert("Push notifications demo", $"{action} action received.", "OK")
                .ContinueWith((task) =>
                {
                    if (task.IsFaulted)
                        throw task.Exception;
                });
        });
    }
    

    Le gestionnaire d’événements pour l’événement ActionTriggered illustre la réception et la propagation des actions de notification Push. Celles-ci sont généralement gérées en mode silencieux, par exemple en accédant à une vue spécifique ou en actualisant certaines données plutôt que d’afficher une alerte.

Configurer l’application Android

Pour configurer votre application .NET MAUI sur Android pour recevoir et traiter des notifications Push :

  1. Dans Visual Studio, ajoutez le package NuGet Xamarin.Firebase.Messaging à votre projet d’application .NET MAUI.

  2. Dans Visual Studio, ajoutez votre fichier google-services.json au dossier Platforms/Android de votre projet d’application .NET MAUI. Une fois le fichier ajouté à votre projet, il doit avoir été ajouté avec une action de génération de GoogleServicesJson:

    <ItemGroup Condition="'$(TargetFramework)' == 'net8.0-android'">
      <GoogleServicesJson Include="Platforms\Android\google-services.json" />
    </ItemGroup>
    

    Conseil

    N’oubliez pas d’ajouter google-services.json à votre fichier .gitignore pour éviter de valider ce fichier dans le contrôle de code source.

  3. Dans Visual Studio, modifiez le fichier projet (*.csproj) et définissez SupportedOSPlatformVersion pour Android sur 26.0 :

    <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'android'">26.0</SupportedOSPlatformVersion>
    

    Google a apporté des modifications aux canaux de notification Android dans l’API 26. Pour plus d’informations, consultez canaux de notification sur developer.android.com.

  4. Dans le dossier Platforms/Android du projet, ajoutez une nouvelle classe nommée DeviceInstallationService et remplacez son code par le code suivant :

    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.";
        }
    }
    

    Cette classe fournit un ID unique, à l’aide de la valeur Secure.AndroidId et de la charge utile d’inscription du hub de notification.

  5. Dans le dossier Platforms/Android du projet, ajoutez une nouvelle classe nommée PushNotificationFirebaseMessagingService et remplacez son code par le code suivant :

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

    Cette classe a un attribut IntentFilter qui inclut le filtre com.google.firebase.MESSAGING_EVENT. Ce filtre permet à Android de transmettre des messages entrants à cette classe pour le traitement.

    Pour plus d’informations sur le format de message Firebase Cloud Messaging, consultez À propos des messages FCM sur developer.android.com.

  6. Dans Visual Studio, ouvrez le fichier MainActivity.cs dans le dossier Platforms/Android et ajoutez les instructions suivantes using :

    using Android.App;
    using Android.Content;
    using Android.Content.PM;
    using Android.OS;
    using PushNotificationsDemo.Services;
    using Firebase.Messaging;
    
  7. Dans la classe MainActivity, définissez LaunchMode sur SingleTop afin que MainActivity ne soit pas recréé lors de l’ouverture :

    [Activity(
        Theme = "@style/Maui.SplashTheme",
        MainLauncher = true,
        LaunchMode = LaunchMode.SingleTop,
        ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize | ConfigChanges.Density)]
    
  8. Dans la classe MainActivity, ajoutez des champs de stockage pour stocker les références aux implémentations IPushDemoNotificationActionService et IDeviceInstallationService :

    IPushDemoNotificationActionService _notificationActionService;
    IDeviceInstallationService _deviceInstallationService;
    
  9. Dans la classe MainActivity, ajoutez NotificationActionService et DeviceInstallationService propriétés privées qui récupèrent leurs implémentations concrètes à partir du conteneur d’injection de dépendances de l’application :

    IPushDemoNotificationActionService NotificationActionService =>
        _notificationActionService ?? (_notificationActionService = IPlatformApplication.Current.Services.GetService<IPushDemoNotificationActionService>());
    
    IDeviceInstallationService DeviceInstallationService =>
        _deviceInstallationService ?? (_deviceInstallationService = IPlatformApplication.Current.Services.GetService<IDeviceInstallationService>());
    
  10. Dans la classe MainActivity, implémentez l’interface de Android.Gms.Tasks.IOnSuccessListener pour récupérer et stocker le jeton Firebase :

    public class MainActivity : MauiAppCompatActivity, Android.Gms.Tasks.IOnSuccessListener
    {
        public void OnSuccess(Java.Lang.Object result)
        {
            DeviceInstallationService.Token = result.ToString();
        }
    }
    
  11. Dans la classe MainActivity, ajoutez la méthode ProcessNotificationActions qui vérifie si une donnée Intent a une valeur supplémentaire nommée action, puis déclenchez de manière conditionnelle ce action à l’aide de l’implémentation IPushDemoNotificationActionService :

    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);
        }
    }
    
  12. Dans la classe MainActivity, remplacez la méthode OnNewIntent pour appeler la méthode ProcessNotificationActions :

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

    Étant donné que LaunchMode pour Activity est défini sur SingleTop, un Intent est envoyé à l’instance de Activity existante via le remplacement OnNewIntent, plutôt que la méthode OnCreate. Par conséquent, vous devez gérer une intention entrante dans OnNewIntent et OnCreate.

  13. Dans la classe MainActivity, remplacez la méthode OnCreate pour appeler la méthode ProcessNotificationActions et récupérer le jeton à partir de Firebase, en ajoutant MainActivity comme IOnSuccessListener:

    protected override void OnCreate(Bundle? savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
    
        if (DeviceInstallationService.NotificationsSupported)
            FirebaseMessaging.Instance.GetToken().AddOnSuccessListener(this);
    
        ProcessNotificationsAction(Intent);
    }
    

    Remarque

    L’application doit être réinscrite chaque fois que vous l’exécutez et l’arrêter d’une session de débogage pour continuer à recevoir des notifications Push.

  14. Dans Visual Studio, ajoutez l’autorisation POST_NOTIFICATIONS au fichier AndroidManifest.xml dans le dossier Platforms/Android :

    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    

    Pour plus d’informations sur cette autorisation, consultez autorisation d’exécution de notification sur developer.android.com.

  15. Dans Visual Studio, ouvrez MainPage.xaml.cs et ajoutez le code suivant à la classe MainPage :

    #if ANDROID
            protected override async void OnAppearing()
            {
                base.OnAppearing();
    
                PermissionStatus status = await Permissions.RequestAsync<Permissions.PostNotifications>();
            }
    #endif
    

    Ce code s’exécute sur Android lorsque le MainPage s’affiche et demande à l’utilisateur d’accorder l’autorisation POST_NOTIFICATIONS. Pour plus d’informations sur les autorisations .NET MAUI, consultez Autorisations.

Configurer l’application iOS

Le simulateur iOS prend en charge les notifications à distance dans iOS 16+ lors de l’exécution dans macOS 13+ sur les ordinateurs Mac avec des processeurs Apple Silicon ou T2. Chaque simulateur génère des jetons d’inscription uniques à la combinaison de ce simulateur et du matériel Mac sur lequel il s’exécute.

Important

Le simulateur prend en charge l’environnement de bac à sable Apple Push Notification Service.

Les instructions suivantes supposent que vous utilisez du matériel qui prend en charge la réception de notifications à distance dans un simulateur iOS. Si ce n’est pas le cas, vous devez exécuter l’application iOS sur un appareil physique, ce qui vous oblige à créer un profil d’approvisionnement pour votre application qui inclut la fonctionnalité Notifications Push. Vous devez ensuite vous assurer que votre application est générée à l’aide de votre certificat et de votre profil d’approvisionnement. Pour plus d’informations sur la procédure à suivre, consultez Configurer votre application iOS pour qu’elle fonctionne avec Azure Notification Hubs, puis suivez les instructions ci-dessous.

Pour configurer votre application .NET MAUI sur iOS pour recevoir et traiter des notifications Push :

  1. Dans Visual Studio, modifiez le fichier projet (*.csproj) et définissez SupportedOSPlatformVersion pour iOS sur 13.0 :

    <SupportedOSPlatformVersion Condition="$([MSBuild]::GetTargetPlatformIdentifier('$(TargetFramework)')) == 'ios'">13.0</SupportedOSPlatformVersion>
    

    Apple a apporté des modifications à son service Push dans iOS 13. Pour plus d’informations, consultez mises à jour d’Azure Notification Hubs pour iOS 13.

  2. Dans Visual Studio, ajoutez un fichier Entitlements.plist au dossier Platforms/iOS du projet et ajoutez le code XML suivant au fichier :

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

    Cela définit le droit d’environnement APS et spécifie d’utiliser l’environnement de service de notification Push Apple de développement. Dans les applications de production, cette valeur de droit doit être définie sur production. Pour plus d’informations sur ce droit, consultez droits d’environnement APS sur developer.apple.com.

    Pour plus d’informations sur l’ajout d’un fichier de droits d’utilisation, consultez droits iOS.

  3. Dans Visual Studio, ajoutez une nouvelle classe nommée DeviceInstallationService au dossier Platforms/iOS du projet et ajoutez le code suivant au fichier :

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

    Cette classe fournit un ID unique, à l’aide de la valeur UIDevice.IdentifierForVendor et de la charge utile d’inscription du hub de notification.

  4. Dans Visual Studio, ajoutez une nouvelle classe nommée NSDataExtensions au dossier Platforms/iOS du projet et ajoutez le code suivant au fichier :

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

    La méthode d’extension ToHexString sera consommée par le code que vous ajouterez qui analyse le jeton d’appareil récupéré.

  5. Dans Visual Studio, ouvrez le fichier AppDelegate.cs dans le dossier Platforms/iOS et ajoutez les instructions using suivantes :

    using System.Diagnostics;
    using Foundation;
    using PushNotificationsDemo.Platforms.iOS;
    using PushNotificationsDemo.Services;
    using UIKit;
    using UserNotifications;
    
  6. Dans la classe AppDelegate, ajoutez des champs de stockage pour stocker les références aux implémentations IPushDemoNotificationActionService, INotificationRegistrationService et IDeviceInstallationService :

    IPushDemoNotificationActionService _notificationActionService;
    INotificationRegistrationService _notificationRegistrationService;
    IDeviceInstallationService _deviceInstallationService;
    
  7. Dans la classe AppDelegate, ajoutez NotificationActionService, NotificationRegistrationService et DeviceInstallationService propriétés privées qui récupèrent leurs implémentations concrètes à partir du conteneur d’injection de dépendances de l’application :

    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>());
    
  8. Dans la classe AppDelegate, ajoutez la méthode CompleteRegistrationAsync pour définir la valeur de propriété IDeviceInstallationService.Token :

    Task CompleteRegistrationAsync(NSData deviceToken)
    {
        DeviceInstallationService.Token = deviceToken.ToHexString();
        return NotificationRegistrationService.RefreshRegistrationAsync();
    }
    

    Cette méthode actualise également l’inscription et met en cache le jeton d’appareil s’il a été mis à jour depuis son dernier stockage.

  9. Dans la classe AppDelegate, ajoutez la méthode ProcessNotificationActions pour le traitement des données de notification NSDictionary et l’appel conditionnel NotificationActionService.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);
        }
    }
    
  10. Dans la classe AppDelegate, ajoutez la méthode RegisteredForRemoteNotifications en passant l’argument deviceToken à la méthode CompleteRegistrationAsync :

    [Export("application:didRegisterForRemoteNotificationsWithDeviceToken:")]
    public void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken)
    {
        CompleteRegistrationAsync(deviceToken)
            .ContinueWith((task) =>
            {
                if (task.IsFaulted)
                    throw task.Exception;
            });
    }
    

    Cette méthode est appelée lorsque l’application est inscrite pour recevoir une notification à distance et est utilisée pour demander le jeton d’appareil unique, qui est effectivement l’adresse de votre application sur l’appareil.

  11. Dans la classe AppDelegate, ajoutez la méthode ReceivedRemoteNotification en passant l’argument userInfo à la méthode ProcessNotificationActions :

    [Export("application:didReceiveRemoteNotification:")]
    public void ReceivedRemoteNotification(UIApplication application, NSDictionary userInfo)
    {
        ProcessNotificationActions(userInfo);
    }
    

    Cette méthode est appelée lorsque l’application a reçu une notification à distance et est utilisée pour traiter la notification.

  12. Dans la classe AppDelegate, ajoutez la méthode FailedToRegisterForRemoteNotifications pour consigner les erreurs suivantes :

    [Export("application:didFailToRegisterForRemoteNotificationsWithError:")]
    public void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error)
    {
        Debug.WriteLine(error.Description);
    }
    

    Cette méthode est appelée lorsque l’application n’a pas pu s’inscrire pour recevoir des notifications à distance. L’inscription peut échouer si l’appareil n’est pas connecté au réseau, si le serveur APNS est inaccessible ou si l’application est correctement configurée.

    Remarque

    Pour les scénarios de production, vous devez implémenter une journalisation et une gestion des erreurs appropriées dans la méthode FailedToRegisterForRemoteNotifications.

  13. Dans la classe AppDelegate, ajoutez la méthode FinishedLaunching pour demander l’autorisation conditionnelle d’utiliser des notifications et de vous inscrire aux notifications à distance :

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

    Pour plus d’informations sur l’autorisation d’utiliser des notifications, consultez Demander l’autorisation d’utiliser des notifications sur developer.apple.com.

Pour plus d’informations sur les notifications dans iOS, consultez notifications utilisateur sur developer.apple.com.

Inscrire des types avec le conteneur d’injection de dépendances de l’application

  1. Dans Visual Studio, ouvrez MauiProgram.cs et ajoutez une instruction using pour l’espace de noms PushNotificationsDemo.Services :

    using PushNotificationsDemo.Services;
    
  2. Dans la classe MauiProgram, ajoutez du code pour la méthode d’extension RegisterServices qui inscrit les DeviceInstallationService sur chaque plateforme, ainsi que les services multiplateformes PushDemoNotificationActionService et NotificationRegistrationService, et qui retourne un objet MauiAppBuilder :

    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;
    }
    
  3. Dans la classe MauiProgram, ajoutez du code pour la méthode d’extension RegisterViews qui inscrit le type MainPage en tant que singleton et qui retourne un objet MauiAppBuilder :

    public static MauiAppBuilder RegisterViews(this MauiAppBuilder builder)
    {
        builder.Services.AddSingleton<MainPage>();
        return builder;
    }
    

    Le type MainPage est inscrit, car il nécessite une dépendance INotificationRegistrationService, et tous les types qui nécessitent une dépendance doivent être inscrits auprès du conteneur d’injection de dépendances.

  4. Dans la classe MauiProgram, modifiez la méthode CreateMauiApp afin qu’elle appelle les méthodes d’extension RegisterServices et RegisterViews :

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

Pour plus d’informations sur l’injection de dépendances dans .NET MAUI, consultez Injection de dépendances.

Tester l'application

Vous pouvez tester votre application en envoyant des notifications Push à l’application à l’aide du service back-end ou via le portail Azure.

Le simulateur iOS prend en charge les notifications à distance dans iOS 16+ lors de l’exécution dans macOS 13+ sur les ordinateurs Mac avec des processeurs Apple Silicon ou T2. Si vous ne répondez pas à ces exigences matérielles, vous devrez tester votre application iOS sur un appareil physique. Sur Android, vous pouvez tester votre application sur un appareil physique déverrouillé par un développeur ou un émulateur.

Android et iOS affichent des notifications Push pour le compte de l’application lorsqu’elle est en cours d’exécution en arrière-plan. Si l’application s’exécute au premier plan lorsque la notification est reçue, le code de l’application détermine le comportement. Par exemple, vous pouvez mettre à jour l’interface de votre application pour refléter les nouvelles informations contenues dans la notification.

Tester à l’aide du service principal

Pour envoyer une notification Push de test à votre application via le service back-end publié sur Azure App Service :

  1. Dans Visual Studio, exécutez l’application PushNotificationsDemo sur Android ou iOS, puis sélectionnez le bouton Inscrire.

    Remarque

    Si vous effectuez des tests sur Android, vérifiez que vous n’exécutez pas à l’aide de la configuration de débogage. Sinon, si l’application a été déployée précédemment, assurez-vous qu’elle a été fermée, puis redémarrez-la à partir du lanceur.

  2. Dans l’outil REST de votre choix, envoyez une demande POST à l’adresse suivante :

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

    Vérifiez que vous configurez les en-têtes de requête pour inclure la clé apikey et sa valeur, définissez le corps sur brut et utilisez le contenu JSON suivant :

    {
        "text": "Message from REST tooling!",
        "action": "action_a"
    }
    

    La requête globale doit être similaire à l’exemple suivant :

    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"
    }
    
  3. Dans l’outil REST de votre choix, vérifiez que vous recevez une réponse 200 OK.

  4. Dans l’application sur Android ou iOS, une alerte doit apparaître montrant action ActionA reçue.

Pour plus d’informations sur l’appel d’API REST, consultez Utiliser des fichiers .http dans Visual Studio et Tester des API web avec le Http Repl. Dans Visual Studio Code, client REST peut être utilisé pour tester les API REST.

Tester à l’aide du portail Azure

Azure Notification Hubs vous permet de vérifier que votre application peut recevoir des notifications Push.

Pour envoyer une notification Push de test à votre application via le portail Azure :

  1. Dans Visual Studio, exécutez l’application PushNotificationsDemo sur Android ou iOS, puis sélectionnez le bouton Inscrire.

    Remarque

    Si vous effectuez des tests sur Android, vérifiez que vous n’exécutez pas à l’aide de la configuration de débogage. Sinon, si l’application a été déployée précédemment, assurez-vous qu’elle a été fermée, puis redémarrez-la à partir du lanceur.

  2. Découvrez comment utiliser Azure Notification Hubs pour envoyer des notifications Push à une application .NET MAUI qui cible Android et iOS.

  3. Dans le panneau Test Send, sélectionnez votre Plateforme requise et modifiez la charge utile.

    Pour Apple, utilisez la charge utile suivante :

    {
      "aps": {
        "alert": "Message from Notification Hub!"
      },
      "action": "action_a"
    }
    

    Pour Android, utilisez la charge utile suivante :

    {
      "message": {
        "notification": {
          "title": "PushDemo",
          "body": "Message from Notification Hub!"
        },
        "data": {
          "action": "action_a"
        }
      }
    }
    

    Le portail Azure doit indiquer que la notification a été envoyée avec succès.

    Pour plus d’informations sur le format de message Firebase Cloud Messaging, consultez À propos des messages FCM sur developer.android.com.

  4. Dans l’application sur Android ou iOS, une alerte doit apparaître montrant action ActionA reçue.

Dépannage

Les sections suivantes décrivent les problèmes courants rencontrés lors de la tentative d’utilisation de notifications Push dans une application cliente.

Aucune réponse du service back-end

Lors du test local, vérifiez que le service back-end est en cours d’exécution et qu’il utilise le port approprié.

Si vous effectuez des tests sur l’application API Azure, vérifiez que le service est en cours d’exécution et a été déployé et a démarré sans erreur.

Vérifiez que vous avez spécifié correctement l’adresse de base dans vos outils REST ou dans votre configuration d’application .NET MAUI. L’adresse de base doit être https://<api_name>.azurewebsites.net ou https://localhost:7020 lors du test local.

Réception d’un code d’état 401 du service back-end

Vérifiez que vous définissez correctement l’en-tête de requête apikey et que cette valeur correspond à celle que vous avez configurée pour le service principal.

Si vous recevez cette erreur lors du test local, vérifiez que la valeur de clé que vous avez définie dans votre application .NET MAUI correspond à la valeur secrets utilisateur Authentication:ApiKey utilisée par le service principal.

Si vous effectuez des tests avec une application API Azure, vérifiez que la valeur clé définie dans votre application .NET MAUI correspond à la valeur de paramètre d’application Authentication:ApiKey définie dans le portail Azure. Si vous avez créé ou modifié ce paramètre d’application après avoir déployé le service principal, vous devez redémarrer le service pour que la valeur prenne effet.

Réception d’un code d’état 404 du service back-end

Vérifiez que le point de terminaison et la méthode de requête HTTP sont corrects :

  • 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

Ou lors du test local :

  • PUT - https://localhost:7020/api/notifications/installations
  • DELETE - https://localhost:7020/api/notifications/installations/<installation_id>
  • POST - https://localhost:7020/api/notifications/requests

Important

Lorsque vous spécifiez l’adresse de base dans l’application .NET MAUI, vérifiez qu’elle se termine par un /. L’adresse de base doit être https://<api_name>.azurewebsites.net ou https://localhost:7020/ lors du test local.

Aucune notification reçue sur Android après le démarrage ou l’arrêt d’une session de débogage

Veillez à vous inscrire chaque fois que vous démarrez une session de débogage. Le débogueur entraîne la génération d’un nouveau jeton Firebase. Par conséquent, l’installation du hub de notification doit être mise à jour.

Inscription impossible et affichage d’un message d’erreur du hub de notification

Vérifiez que l’appareil de test dispose d’une connectivité réseau. Déterminez ensuite le code d’état de la réponse HTTP en définissant un point d’arrêt pour inspecter la propriété StatusCode dans le HttpResponse.

Passez en revue les suggestions de résolution des problèmes précédentes, le cas échéant, en fonction du code d’état.

Définissez un point d’arrêt sur les lignes qui retournent des codes d’état spécifiques pour l’API respective. Essayez ensuite d’appeler le service back-end lors du débogage local.

Vérifiez que le service principal fonctionne comme prévu par vos outils REST de votre choix et utilisez la charge utile créée par l’application .NET MAUI pour votre plateforme choisie.

Passez en revue les sections de configuration propres à la plateforme pour vous assurer qu’aucune étape n’a été manquée. Vérifiez que les valeurs appropriées sont résolues pour InstallationId et Token variables pour votre plateforme choisie.

Impossible de résoudre un ID pour l’appareil que le message d’erreur de l’appareil

Passez en revue les sections de configuration propres à la plateforme pour vous assurer qu’aucune étape n’a été manquée.