Partager via


Tutoriel : Envoyer des notifications Push vers des applications Android spécifiques à l’aide d’Azure Notification Hubs

Remarque

Pour plus d’informations sur les étapes de dépréciation et de migration de Firebase Cloud Messaging, consultez Migration de Google Firebase Cloud Messaging.

Ce didacticiel explique comment utiliser Azure Notification Hubs pour envoyer des notifications Push à un utilisateur particulier d'une application sur un appareil spécifique. Un code WebAPI principal ASP.NET est utilisé pour authentifier les clients et pour générer les notifications, comme le présente l’article Inscription auprès du serveur principal de votre application. Ce tutoriel s’appuie sur le hub de notification que vous avez créé dans le Tutoriel : Notifications Push vers des appareils Android à l’aide d’Azure Notification Hubs et de Firebase Cloud Messaging.

Dans ce tutoriel, vous effectuez les étapes suivantes :

  • Créer le projet d’API Web principale qui authentifie les utilisateurs.
  • Mettre à jour une application Android.
  • Test de l'application

Prérequis

Suivre le Tutoriel : Notifications Push vers des appareils Android avec Azure Notification Hubs et Firebase Cloud Messaging avant de passer à ce tutoriel.

Création du projet WebAPI

Les sections suivantes traitent de la création d’un serveur principal WebAPI ASP.NET. Ce processus a trois objectifs principaux :

  • Authentification des clients : ajoutez un gestionnaire de messages pour authentifier les demandes des clients et associer l’utilisateur à la demande.
  • Inscriptions aux notifications à l’aide du serveur principal WebAPI : ajoutez un contrôleur pour gérer les nouvelles inscriptions afin qu’un appareil client puisse recevoir des notifications. Le nom d’utilisateur authentifié est automatiquement ajouté à l’inscription en tant que balise.
  • Envoi de notifications aux clients : ajoutez un contrôleur permettant aux utilisateurs de déclencher une notification push sécurisée pour les appareils et les clients associés à la balise.

Pour créer le serveur principal ASP.NET Core 6.0, procédez comme suit :

Pour ce faire, lancez Visual Studio. Dans le menu Outils, sélectionnez Extensions et mises à jour. Recherchez Gestionnaire de package NuGet pour votre version de Visual Studio et vérifiez que vous disposez de la dernière version. Si vous ne disposez pas de la version la plus récente, désinstallez votre version actuelle et réinstallez le Gestionnaire de package NuGet.

Screenshot of the Extensions and Updates dialog box with the NuGet Package manage for Visual Studios package highlighted.

Remarque

Assurez-vous que le Kit de développement logiciel (SDK) Azure Visual Studio est installé, pour le déploiement du site web.

  1. Démarrez Visual Studio ou Visual Studio Express.

  2. Sélectionnez Explorateur de serveurs et connectez-vous à votre compte Azure. Pour créer les ressources du site web sur votre compte, vous devez être connecté.

  3. Dans Visual Studio, dans le menu Fichier, sélectionnez Nouveau>Projet.

  4. Entrez API web dans le champ de recherche.

  5. Sélectionnez le modèle de projet API web ASP.NET Core, puis Suivant.

  6. Dans la boîte de dialogue Configurer votre nouveau projet, nommez le projet AppBackend, puis sélectionnez Suivant.

  7. Dans la boîte de dialogue Informations supplémentaires :

    • Vérifiez que le framework est .NET 6.0 (prise en charge à long terme).
    • Vérifiez que la case à cocher Utiliser des contrôleurs (décocher pour utiliser les API minimales) est cochée.
    • Décochez Activer la prise en charge d’OpenAPI.
    • Sélectionnez Create (Créer).

Supprimer les fichiers de modèle WeatherForecast

  1. Supprimez les fichiers d’exemple WeatherForecast.cs et Controllers/WeatherForecastController.cs du nouveau projet AppBackend.
  2. Ouvrez Properties\launchSettings.json.
  3. Modifiez les propriétés launchUrl de weatherforcast en appbackend.

Dans la fenêtre Configurer l’application web Microsoft Azure, sélectionnez l’abonnement puis effectuez l’une des actions suivantes dans la liste Plan App Service :

  • Sélectionnez un plan Azure App Service que vous avez déjà créé.
  • Sélectionnez Créer un plan App Service, et créez-en un.

Vous n'avez pas besoin de base de données pour ce didacticiel. Une fois que vous avez sélectionné votre plan App Service, sélectionnez OK pour créer le projet.

The Configure Microsoft Azure Web App window

Si vous ne voyez pas la page Configurer le plan App Service, poursuivez le tutoriel. Vous pourrez le configurer plus tard, lors de la publication de l’application.

Authentification des clients sur le serveur principal WebAPI

Dans cette section, vous créez une classe de gestionnaire de messages nommée AuthenticationTestHandler pour le nouveau serveur principal. Cette classe est dérivée de DelegatingHandler et ajoutée comme gestionnaire de messages afin de pouvoir traiter toutes les demandes entrantes dans le serveur principal.

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet AppBackend, puis sélectionnez Ajouter et Classe.

  2. Nommez la nouvelle classe AuthenticationTestHandler.cs, puis sélectionnez Ajouter pour générer la classe. Par souci de simplification, cette classe permet d’authentifier les utilisateurs via l’ Authentification de base . Votre application peut utiliser n’importe quel schéma d’authentification.

  3. Dans AuthenticationTestHandler.cs, ajoutez les instructions using suivantes :

    using System.Net.Http;
    using System.Threading;
    using System.Security.Principal;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    
  4. Dans AuthenticationTestHandler.cs, remplacez la définition de classe AuthenticationTestHandler par le code suivant :

    Ce gestionnaire autorise la demande lorsque les trois conditions suivantes sont vraies :

    • La demande comprenait un en-tête d’autorisation.
    • La demande utilise l’authentification de base .
    • Les chaînes du nom d’utilisateur et du mot de passe sont identiques.

    Sinon, la demande est rejetée. Cette authentification ne répond pas à une véritable approche d’authentification et d’autorisation. Il s’agit uniquement d’un exemple très simple pour ce didacticiel.

    Si le message de la demande est authentifié et autorisé par AuthenticationTestHandler, l’utilisateur de l’authentification de base est attaché à la demande actuelle sur HttpContext. Les informations utilisateur dans HttpContext sont utilisées ultérieurement par un autre contrôleur (RegisterController) pour ajouter une balise à la demande d’inscription aux notifications.

    public class AuthenticationTestHandler : DelegatingHandler
    {
        protected override Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
        {
            var authorizationHeader = request.Headers.GetValues("Authorization").First();
    
            if (authorizationHeader != null && authorizationHeader
                .StartsWith("Basic ", StringComparison.InvariantCultureIgnoreCase))
            {
                string authorizationUserAndPwdBase64 =
                    authorizationHeader.Substring("Basic ".Length);
                string authorizationUserAndPwd = Encoding.Default
                    .GetString(Convert.FromBase64String(authorizationUserAndPwdBase64));
                string user = authorizationUserAndPwd.Split(':')[0];
                string password = authorizationUserAndPwd.Split(':')[1];
    
                if (VerifyUserAndPwd(user, password))
                {
                    // Attach the new principal object to the current HttpContext object
                    HttpContext.Current.User =
                        new GenericPrincipal(new GenericIdentity(user), new string[0]);
                    System.Threading.Thread.CurrentPrincipal =
                        System.Web.HttpContext.Current.User;
                }
                else return Unauthorized();
            }
            else return Unauthorized();
    
            return base.SendAsync(request, cancellationToken);
        }
    
        private bool VerifyUserAndPwd(string user, string password)
        {
            // This is not a real authentication scheme.
            return user == password;
        }
    
        private Task<HttpResponseMessage> Unauthorized()
        {
            var response = new HttpResponseMessage(HttpStatusCode.Forbidden);
            var tsc = new TaskCompletionSource<HttpResponseMessage>();
            tsc.SetResult(response);
            return tsc.Task;
        }
    }
    

    Notes

    Note de sécurité : la classe AuthenticationTestHandler n’offre pas de véritable authentification. Elle sert uniquement à simuler l’authentification de base et n’est pas sécurisée. Vous devez mettre en œuvre un mécanisme d’authentification sécurisé dans vos applications de production et vos services.

  5. Pour enregistrer le gestionnaire de messages, ajoutez le code suivant à la fin de la méthode Register dans le fichier Program.cs :

    config.MessageHandlers.Add(new AuthenticationTestHandler());
    
  6. Enregistrez vos modifications.

Inscription aux notifications à l’aide du serveur principal WebAPI

Dans cette section, vous ajoutez un nouveau contrôleur au serveur principal WebAPI pour gérer les demandes d’inscription d’un utilisateur et d’un appareil aux notifications à l’aide de la bibliothèque cliente pour les hubs de notification. Le contrôleur ajoute une balise d’utilisateur pour l’utilisateur qui a été authentifié et attaché à HttpContext par AuthenticationTestHandler. La balise a le format de chaîne "username:<actual username>".

  1. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet AppBackend, puis sélectionnez Gérer les packages NuGet.

  2. Dans le volet gauche, sélectionnez En ligne puis tapez Microsoft.Azure.NotificationHubs dans la zone Recherche.

  3. Dans la liste de résultats, sélectionnez Microsoft Azure Notification Hubs, puis Installer. Procédez à l’installation, puis fermez la fenêtre du Gestionnaire de package NuGet.

    Cette action ajoute une référence au Kit de développement logiciel (SDK) Azure Notification Hubs à l’aide du package NuGet Microsoft.Azure.Notification Hubs.

  4. Créez un nouveau fichier de classe qui représente la connexion avec le hub de notification utilisé pour envoyer des notifications. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le dossier Modèles, sélectionnez Ajouter, puis Classe. Nommez la nouvelle classe Notifications.cs, puis sélectionnez Ajouter pour générer la classe.

    The Add New Item window

  5. Dans Notifications.cs, ajoutez l’instruction using suivante en haut du fichier :

    using Microsoft.Azure.NotificationHubs;
    
  6. Remplacez la définition de classe Notifications par le code suivant et les deux espaces réservés par la chaîne de connexion (avec accès complet) de votre centre Notification Hubs et le nom du hub (disponible sur le Portail Azure) :

    public class Notifications
    {
        public static Notifications Instance = new Notifications();
    
        public NotificationHubClient Hub { get; set; }
    
        private Notifications() {
            Hub = NotificationHubClient.CreateClientFromConnectionString("<your hub's DefaultFullSharedAccessSignature>",
                                                                            "<hub name>");
        }
    }
    

    Important

    Entrez le nom et la DefaultFullSharedAccessSignature de votre hub avant de continuer.

  7. Ensuite, créez un contrôleur nommé RegisterController. Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le dossier Contrôleurs, sélectionnez Ajouter, puis Contrôleur.

  8. Sélectionnez Contrôleur API - Vide, puis Ajouter.

  9. Dans la boîte Nom du contrôleur, tapez RegisterController pour nommer la nouvelle classe, puis sélectionnez Ajouter.

    The Add Controller window.

  10. Dans RegisterController.cs, ajoutez les instructions using suivantes :

    using Microsoft.Azure.NotificationHubs;
    using Microsoft.Azure.NotificationHubs.Messaging;
    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  11. Ajoutez le code suivant dans la définition de classe RegisterController . Dans ce code, vous ajoutez une balise d’utilisateur pour l’utilisateur attaché à HttpContext. L’utilisateur a été authentifié et attaché à HttpContext par le filtre de messages que vous avez ajouté, AuthenticationTestHandler. Vous pouvez également ajouter des contrôles facultatifs afin de vérifier que l’utilisateur dispose des droits d’inscription nécessaires pour les balises requises.

    private NotificationHubClient hub;
    
    public RegisterController()
    {
        hub = Notifications.Instance.Hub;
    }
    
    public class DeviceRegistration
    {
        public string Platform { get; set; }
        public string Handle { get; set; }
        public string[] Tags { get; set; }
    }
    
    // POST api/register
    // This creates a registration id
    public async Task<string> Post(string handle = null)
    {
        string newRegistrationId = null;
    
        // make sure there are no existing registrations for this push handle (used for iOS and Android)
        if (handle != null)
        {
            var registrations = await hub.GetRegistrationsByChannelAsync(handle, 100);
    
            foreach (RegistrationDescription registration in registrations)
            {
                if (newRegistrationId == null)
                {
                    newRegistrationId = registration.RegistrationId;
                }
                else
                {
                    await hub.DeleteRegistrationAsync(registration);
                }
            }
        }
    
        if (newRegistrationId == null) 
            newRegistrationId = await hub.CreateRegistrationIdAsync();
    
        return newRegistrationId;
    }
    
    // PUT api/register/5
    // This creates or updates a registration (with provided channelURI) at the specified id
    public async Task<HttpResponseMessage> Put(string id, DeviceRegistration deviceUpdate)
    {
        RegistrationDescription registration = null;
        switch (deviceUpdate.Platform)
        {
            case "mpns":
                registration = new MpnsRegistrationDescription(deviceUpdate.Handle);
                break;
            case "wns":
                registration = new WindowsRegistrationDescription(deviceUpdate.Handle);
                break;
            case "apns":
                registration = new AppleRegistrationDescription(deviceUpdate.Handle);
                break;
            case "fcm":
                registration = new FcmRegistrationDescription(deviceUpdate.Handle);
                break;
            default:
                throw new HttpResponseException(HttpStatusCode.BadRequest);
        }
    
        registration.RegistrationId = id;
        var username = HttpContext.Current.User.Identity.Name;
    
        // add check if user is allowed to add these tags
        registration.Tags = new HashSet<string>(deviceUpdate.Tags);
        registration.Tags.Add("username:" + username);
    
        try
        {
            await hub.CreateOrUpdateRegistrationAsync(registration);
        }
        catch (MessagingException e)
        {
            ReturnGoneIfHubResponseIsGone(e);
        }
    
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    
    // DELETE api/register/5
    public async Task<HttpResponseMessage> Delete(string id)
    {
        await hub.DeleteRegistrationAsync(id);
        return Request.CreateResponse(HttpStatusCode.OK);
    }
    
    private static void ReturnGoneIfHubResponseIsGone(MessagingException e)
    {
        var webex = e.InnerException as WebException;
        if (webex.Status == WebExceptionStatus.ProtocolError)
        {
            var response = (HttpWebResponse)webex.Response;
            if (response.StatusCode == HttpStatusCode.Gone)
                throw new HttpRequestException(HttpStatusCode.Gone.ToString());
        }
    }
    
  12. Enregistrez vos modifications.

Envoyer des notifications depuis le serveur principal WebAPI

Dans cette section, vous ajoutez un nouveau contrôleur qui montre aux appareils clients comment envoyer une notification. La notification se base sur la balise du nom d’utilisateur qui utilise la bibliothèque .NET du service d’Azure Notification Hubs dans le serveur principal WebAPI ASP.NET.

  1. Créez un nouveau contrôleur nommé NotificationsController, de la même façon que vous avez créé RegisterController dans la section précédente.

  2. Dans NotificationsController.cs, ajoutez les instructions using suivantes :

    using AppBackend.Models;
    using System.Threading.Tasks;
    using System.Web;
    
  3. Ajoutez la méthode suivante à la classe NotificationsController :

    Ce code envoie un type de notification basé sur le paramètre pns du service de notification de plateforme. La valeur de to_tag permet de définir la balise username sur le message. Cette balise doit correspondre à une balise de nom d’utilisateur d’une inscription de hub de notification active. Le message de notification est extrait du corps de la demande POST et mis en forme pour le PNS cible.

    Selon le service Platform Notification Service (PNS) que vos appareils pris en charge utilisent pour recevoir des notifications, ces dernières sont prises en charge dans plusieurs formats. Par exemple sur des appareils Windows, vous pouvez utiliser une notification toast avec WNS qui n’est pas directement prise en charge par un autre service PNS. Dans une instance de ce type, votre serveur principal doit formater la notification dans un format pris en charge pour le service PNS des appareils que vous envisagez de prendre en charge. Utilisez ensuite l’API d’envoi appropriée sur la classe NotificationHubClient.

    public async Task<HttpResponseMessage> Post(string pns, [FromBody]string message, string to_tag)
    {
        var user = HttpContext.Current.User.Identity.Name;
        string[] userTag = new string[2];
        userTag[0] = "username:" + to_tag;
        userTag[1] = "from:" + user;
    
        Microsoft.Azure.NotificationHubs.NotificationOutcome outcome = null;
        HttpStatusCode ret = HttpStatusCode.InternalServerError;
    
        switch (pns.ToLower())
        {
            case "wns":
                // Windows 8.1 / Windows Phone 8.1
                var toast = @"<toast><visual><binding template=""ToastText01""><text id=""1"">" + 
                            "From " + user + ": " + message + "</text></binding></visual></toast>";
                outcome = await Notifications.Instance.Hub.SendWindowsNativeNotificationAsync(toast, userTag);
                break;
            case "apns":
                // iOS
                var alert = "{\"aps\":{\"alert\":\"" + "From " + user + ": " + message + "\"}}";
                outcome = await Notifications.Instance.Hub.SendAppleNativeNotificationAsync(alert, userTag);
                break;
            case "fcm":
                // Android
                var notif = "{ \"data\" : {\"message\":\"" + "From " + user + ": " + message + "\"}}";
                outcome = await Notifications.Instance.Hub.SendFcmNativeNotificationAsync(notif, userTag);
                break;
        }
    
        if (outcome != null)
        {
            if (!((outcome.State == Microsoft.Azure.NotificationHubs.NotificationOutcomeState.Abandoned) ||
                (outcome.State == Microsoft.Azure.NotificationHubs.NotificationOutcomeState.Unknown)))
            {
                ret = HttpStatusCode.OK;
            }
        }
    
        return Request.CreateResponse(ret);
    }
    
  4. Appuyez sur la touche F5 pour exécuter l’application et vérifier le travail que vous avez accompli jusqu’à présent. L’application ouvre un navigateur web, qui s’affiche sur la page d’accueil ASP.NET.

Publication du nouveau serveur principal WebAPI

Ensuite, vous déployez l’application sur un site web Azure afin de la rendre accessible à tous les appareils.

  1. Cliquez avec le bouton droit sur le projet AppBackend, puis sélectionnez Publier.

  2. Sélectionnez Microsoft Azure App Service comme cible de publication, puis cliquez sur \*\*Publier. La fenêtre Créer App Service s’ouvre. Vous pouvez créer toutes les ressources Azure nécessaires pour exécuter l’application web ASP.NET dans Azure.

    The Microsoft Azure App Service tile

  3. Dans la fenêtre Créer App Service, sélectionnez votre compte Azure. Sélectionnez Modifier le type>Application web. Conservez le nom de l’application web par défaut et sélectionnez l’abonnement, le groupe de ressources et le plan App Service.

  4. Sélectionnez Create (Créer).

  5. Notez la valeur de la propriété URL du site dans la section Résumé. Cette URL constitue le point de terminaison de votre serveur principal plus loin dans ce didacticiel.

  6. Sélectionnez Publier.

Après en avoir terminé avec l’Assistant, il publie l’application web ASP.NET dans Azure, puis ouvre l’application dans le navigateur par défaut. Votre application est visible dans Azure App Services.

L’URL utilise le nom de l’application web que vous avez spécifié précédemment, au format http://<app_name>.azurewebsites.net.

Création du projet Android

L’étape suivante consiste à mettre à jour l’application Android créée dans le Tutoriel : Notifications Push vers des appareils Android à l’aide d’Azure Notification Hubs et de Firebase Cloud Messaging.

  1. Ouvrez votre fichier res/layout/activity_main.xml, remplacez les définitions de contenu suivantes :

    Cette opération ajoute de nouveaux contrôles EditText pour la connexion en tant qu'utilisateur. Un champ est également ajouté pour une balise de nom d'utilisateur qui fera partie des notifications que vous enverrez :

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    
    <EditText
        android:id="@+id/usernameText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="@string/usernameHint"
        android:layout_above="@+id/passwordText"
        android:layout_alignParentEnd="true" />
    <EditText
        android:id="@+id/passwordText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:hint="@string/passwordHint"
        android:inputType="textPassword"
        android:layout_above="@+id/buttonLogin"
        android:layout_alignParentEnd="true" />
    <Button
        android:id="@+id/buttonLogin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/loginButton"
        android:onClick="login"
        android:layout_above="@+id/toggleButtonFCM"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="24dp" />
    <ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textOn="WNS on"
        android:textOff="WNS off"
        android:id="@+id/toggleButtonWNS"
        android:layout_toLeftOf="@id/toggleButtonFCM"
        android:layout_centerVertical="true" />
    <ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textOn="FCM on"
        android:textOff="FCM off"
        android:id="@+id/toggleButtonFCM"
        android:checked="true"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />
    <ToggleButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textOn="APNS on"
        android:textOff="APNS off"
        android:id="@+id/toggleButtonAPNS"
        android:layout_toRightOf="@id/toggleButtonFCM"
        android:layout_centerVertical="true" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editTextNotificationMessageTag"
        android:layout_below="@id/toggleButtonFCM"
        android:layout_centerHorizontal="true"
        android:hint="@string/notification_message_tag_hint" />
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/editTextNotificationMessage"
        android:layout_below="@+id/editTextNotificationMessageTag"
        android:layout_centerHorizontal="true"
        android:hint="@string/notification_message_hint" />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/send_button"
        android:id="@+id/sendbutton"
        android:onClick="sendNotificationButtonOnClick"
        android:layout_below="@+id/editTextNotificationMessage"
        android:layout_centerHorizontal="true" />
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        android:id="@+id/text_hello"
        />
    </RelativeLayout>
    
  2. Ouvrez votre fichier res/values/strings.xml et remplacez la définition send_button par les lignes suivantes qui redéfinissent la chaîne du send_button et ajoutent des chaînes pour les autres contrôles :

    <string name="usernameHint">Username</string>
    <string name="passwordHint">Password</string>
    <string name="loginButton">1. Sign in</string>
    <string name="send_button">2. Send Notification</string>
    <string name="notification_message_hint">Notification message</string>
    <string name="notification_message_tag_hint">Recipient username</string>
    

    La présentation graphique de votre fichier main_activity.xml doit maintenant ressembler à l’image suivante :

    Screenshot of an emulator displaying what the main activity X M L graphical layout will look like.

  3. Créez une classe nommée RegisterClient dans le même package que votre classe MainActivity. Utilisez le code ci-dessous pour le nouveau fichier de classe.

    
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Set;
    
    import org.apache.http.HttpResponse;
    import org.apache.http.HttpStatus;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.client.methods.HttpPut;
    import org.apache.http.client.methods.HttpUriRequest;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.apache.http.util.EntityUtils;
    import org.json.JSONArray;
    import org.json.JSONException;
    import org.json.JSONObject;
    
    import android.content.Context;
    import android.content.SharedPreferences;
    import android.util.Log;
    
    public class RegisterClient {
        private static final String PREFS_NAME = "ANHSettings";
        private static final String REGID_SETTING_NAME = "ANHRegistrationId";
        private String Backend_Endpoint;
        SharedPreferences settings;
        protected HttpClient httpClient;
        private String authorizationHeader;
    
        public RegisterClient(Context context, String backendEndpoint) {
            super();
            this.settings = context.getSharedPreferences(PREFS_NAME, 0);
            httpClient =  new DefaultHttpClient();
            Backend_Endpoint = backendEndpoint + "/api/register";
        }
    
        public String getAuthorizationHeader() {
            return authorizationHeader;
        }
    
        public void setAuthorizationHeader(String authorizationHeader) {
            this.authorizationHeader = authorizationHeader;
        }
    
        public void register(String handle, Set<String> tags) throws ClientProtocolException, IOException, JSONException {
            String registrationId = retrieveRegistrationIdOrRequestNewOne(handle);
    
            JSONObject deviceInfo = new JSONObject();
            deviceInfo.put("Platform", "fcm");
            deviceInfo.put("Handle", handle);
            deviceInfo.put("Tags", new JSONArray(tags));
    
            int statusCode = upsertRegistration(registrationId, deviceInfo);
    
            if (statusCode == HttpStatus.SC_OK) {
                return;
            } else if (statusCode == HttpStatus.SC_GONE){
                settings.edit().remove(REGID_SETTING_NAME).commit();
                registrationId = retrieveRegistrationIdOrRequestNewOne(handle);
                statusCode = upsertRegistration(registrationId, deviceInfo);
                if (statusCode != HttpStatus.SC_OK) {
                    Log.e("RegisterClient", "Error upserting registration: " + statusCode);
                    throw new RuntimeException("Error upserting registration");
                }
            } else {
                Log.e("RegisterClient", "Error upserting registration: " + statusCode);
                throw new RuntimeException("Error upserting registration");
            }
        }
    
        private int upsertRegistration(String registrationId, JSONObject deviceInfo)
                throws UnsupportedEncodingException, IOException,
                ClientProtocolException {
            HttpPut request = new HttpPut(Backend_Endpoint+"/"+registrationId);
            request.setEntity(new StringEntity(deviceInfo.toString()));
            request.addHeader("Authorization", "Basic "+authorizationHeader);
            request.addHeader("Content-Type", "application/json");
            HttpResponse response = httpClient.execute(request);
            int statusCode = response.getStatusLine().getStatusCode();
            return statusCode;
        }
    
        private String retrieveRegistrationIdOrRequestNewOne(String handle) throws ClientProtocolException, IOException {
            if (settings.contains(REGID_SETTING_NAME))
                return settings.getString(REGID_SETTING_NAME, null);
    
            HttpUriRequest request = new HttpPost(Backend_Endpoint+"?handle="+handle);
            request.addHeader("Authorization", "Basic "+authorizationHeader);
            HttpResponse response = httpClient.execute(request);
            if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                Log.e("RegisterClient", "Error creating registrationId: " + response.getStatusLine().getStatusCode());
                throw new RuntimeException("Error creating Notification Hubs registrationId");
            }
            String registrationId = EntityUtils.toString(response.getEntity());
            registrationId = registrationId.substring(1, registrationId.length()-1);
    
            settings.edit().putString(REGID_SETTING_NAME, registrationId).commit();
    
            return registrationId;
        }
    }
    

    Ce composant met en œuvre les appels REST nécessaires pour contacter le backend de l’application et inscrire cette dernière pour les notifications Push. Il enregistre également en local les informations registrationIds créées par le hub de notification, comme expliqué dans la rubrique Inscription auprès du serveur principal de votre application. Elle utilise un jeton d’autorisation stocké dans le stockage local lorsque vous cliquez sur le bouton Se connecter.

  4. Dans votre classe MainActivity, ajoutez un champ pour la classe RegisterClient et une chaîne pour le point de terminaison de votre backend ASP.NET. Remplacez bien <Enter Your Backend Endpoint> par le point de terminaison réel de votre serveur principal, obtenu précédemment. Par exemple : http://mybackend.azurewebsites.net.

    private RegisterClient registerClient;
    private static final String BACKEND_ENDPOINT = "<Enter Your Backend Endpoint>";
    FirebaseInstanceId fcm;
    String FCM_token = null;
    
  5. Dans votre classe MainActivity, dans la méthode onCreate, supprimez ou commentez l'initialisation du champ hub et l'appel à la méthode registerWithNotificationHubs. Ensuite, ajoutez du code pour initialiser une instance de la classe RegisterClient . La méthode doit contenir les lignes qui suivent :

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        mainActivity = this;
        FirebaseService.createChannelAndHandleNotifications(getApplicationContext());
        fcm = FirebaseInstanceId.getInstance();
        registerClient = new RegisterClient(this, BACKEND_ENDPOINT);
        setContentView(R.layout.activity_main);
    }
    
  6. Ajoutez les instructions import suivantes à votre fichier MainActivity.java.

    import android.util.Base64;
    import android.view.View;
    import android.widget.EditText;
    
    import android.widget.Button;
    import android.widget.ToggleButton;
    import java.io.UnsupportedEncodingException;
    import android.content.Context;
    import java.util.HashSet;
    import android.widget.Toast;
    import org.apache.http.client.ClientProtocolException;
    import java.io.IOException;
    import org.apache.http.HttpStatus;
    
    import android.os.AsyncTask;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    
    import android.app.AlertDialog;
    import android.content.DialogInterface;
    
    import com.google.firebase.iid.FirebaseInstanceId;
    import com.google.firebase.iid.InstanceIdResult;
    import com.google.android.gms.tasks.OnSuccessListener;
    import java.util.concurrent.TimeUnit;
    
  7. Remplacez le code dans la méthode onStart par le code suivant :

    super.onStart();
    Button sendPush = (Button) findViewById(R.id.sendbutton);
    sendPush.setEnabled(false);
    
  8. Ensuite, ajoutez les méthodes suivantes pour gérer l’événement de clic sur le bouton Se connecter et l’envoi de notifications Push.

    public void login(View view) throws UnsupportedEncodingException {
        this.registerClient.setAuthorizationHeader(getAuthorizationHeader());
    
        final Context context = this;
        new AsyncTask<Object, Object, Object>() {
            @Override
            protected Object doInBackground(Object... params) {
                try {
    
                    FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(new OnSuccessListener<InstanceIdResult>() {
                        @Override
                        public void onSuccess(InstanceIdResult instanceIdResult) {
                            FCM_token = instanceIdResult.getToken();
                            Log.d(TAG, "FCM Registration Token: " + FCM_token);
                        }
                    });
                    TimeUnit.SECONDS.sleep(1);
                    registerClient.register(FCM_token, new HashSet<String>());
                } catch (Exception e) {
                    DialogNotify("MainActivity - Failed to register", e.getMessage());
                    return e;
                }
                return null;
            }
    
            protected void onPostExecute(Object result) {
                Button sendPush = (Button) findViewById(R.id.sendbutton);
                sendPush.setEnabled(true);
                Toast.makeText(context, "Signed in and registered.",
                        Toast.LENGTH_LONG).show();
            }
        }.execute(null, null, null);
    }
    
    private String getAuthorizationHeader() throws UnsupportedEncodingException {
        EditText username = (EditText) findViewById(R.id.usernameText);
        EditText password = (EditText) findViewById(R.id.passwordText);
        String basicAuthHeader = username.getText().toString()+":"+password.getText().toString();
        basicAuthHeader = Base64.encodeToString(basicAuthHeader.getBytes("UTF-8"), Base64.NO_WRAP);
        return basicAuthHeader;
    }
    
    /**
        * This method calls the ASP.NET WebAPI backend to send the notification message
        * to the platform notification service based on the pns parameter.
        *
        * @param pns     The platform notification service to send the notification message to. Must
        *                be one of the following ("wns", "fcm", "apns").
        * @param userTag The tag for the user who will receive the notification message. This string
        *                must not contain spaces or special characters.
        * @param message The notification message string. This string must include the double quotes
        *                to be used as JSON content.
        */
    public void sendPush(final String pns, final String userTag, final String message)
            throws ClientProtocolException, IOException {
        new AsyncTask<Object, Object, Object>() {
            @Override
            protected Object doInBackground(Object... params) {
                try {
    
                    String uri = BACKEND_ENDPOINT + "/api/notifications";
                    uri += "?pns=" + pns;
                    uri += "&to_tag=" + userTag;
    
                    HttpPost request = new HttpPost(uri);
                    request.addHeader("Authorization", "Basic "+ getAuthorizationHeader());
                    request.setEntity(new StringEntity(message));
                    request.addHeader("Content-Type", "application/json");
    
                    HttpResponse response = new DefaultHttpClient().execute(request);
    
                    if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                        DialogNotify("MainActivity - Error sending " + pns + " notification",
                                response.getStatusLine().toString());
                        throw new RuntimeException("Error sending notification");
                    }
                } catch (Exception e) {
                    DialogNotify("MainActivity - Failed to send " + pns + " notification ", e.getMessage());
                    return e;
                }
    
                return null;
            }
        }.execute(null, null, null);
    }
    

    Le gestionnaire login pour le bouton Se connecter génère une utilisation du jeton d'authentification de base sur l’entrée de nom d’utilisateur et de mot de passe (qui représente n’importe quel jeton utilisé par votre schéma d’authentification), puis il utilise RegisterClient pour appeler le principal et s’inscrire.

    La méthode sendPush appelle le serveur principal pour déclencher une notification sécurisée pour l'utilisateur basée sur la balise d'utilisateur. Le service de notification de la plateforme ciblé par sendPush varie selon la chaîne pns passée.

  9. Ajoutez la méthode DialogNotify suivante à la classe MainActivity.

    protected void DialogNotify(String title, String message)
    {
        AlertDialog alertDialog = new AlertDialog.Builder(MainActivity.this).create();
        alertDialog.setTitle(title);
        alertDialog.setMessage(message);
        alertDialog.setButton(AlertDialog.BUTTON_NEUTRAL, "OK",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }
                });
        alertDialog.show();
    }
    
  10. Dans votre classe MainActivity, mettez à jour la méthode sendNotificationButtonOnClick pour appeler la méthode sendPush avec les services de notification de plateforme sélectionnés par l'utilisateur, comme suit.

    /**
    * Send Notification button click handler. This method sends the push notification
    * message to each platform selected.
    *
    * @param v The view
    */
    public void sendNotificationButtonOnClick(View v)
            throws ClientProtocolException, IOException {
    
        String nhMessageTag = ((EditText) findViewById(R.id.editTextNotificationMessageTag))
                .getText().toString();
        String nhMessage = ((EditText) findViewById(R.id.editTextNotificationMessage))
                .getText().toString();
    
        // JSON String
        nhMessage = "\"" + nhMessage + "\"";
    
        if (((ToggleButton)findViewById(R.id.toggleButtonWNS)).isChecked())
        {
            sendPush("wns", nhMessageTag, nhMessage);
        }
        if (((ToggleButton)findViewById(R.id.toggleButtonFCM)).isChecked())
        {
            sendPush("fcm", nhMessageTag, nhMessage);
        }
        if (((ToggleButton)findViewById(R.id.toggleButtonAPNS)).isChecked())
        {
            sendPush("apns", nhMessageTag, nhMessage);
        }
    }
    
  11. Dans le fichier build.gradle, ajoutez la ligne suivante à la section android après la section buildTypes.

    useLibrary 'org.apache.http.legacy'
    
  12. Si votre application cible le niveau d’API 28 (Android 9.0) ou supérieur, incluez la déclaration suivante dans l’élément <application> de AndroidManifest.xml.

    <uses-library
        android:name="org.apache.http.legacy"
        android:required="false" />
    
  13. Créez le projet.

Test de l'application

  1. Exécutez l'application sur un appareil ou un émulateur à l'aide d'Android Studio.

  2. Dans l'application Android, entrez un nom d'utilisateur et un mot de passe. Ils doivent représenter la même valeur de chaîne et ne pas contenir d'espaces ou de caractères spéciaux.

  3. Dans l’application Android, cliquez sur Se connecter. Attendez que s’affiche un message indiquant Signed in and registered (Connecté et inscrit). Le bouton Send Notification est alors activé.

    Screenshot of an emulator showing what the Notification Hubs Notify Users app looks like after logging in.

  4. Cliquez sur les boutons bascule pour activer toutes les plateformes où vous avez exécuté l'application et inscrit un utilisateur.

  5. Entrez le nom de l'utilisateur qui reçoit le message de notification. Cet utilisateur doit être inscrit pour les notifications sur les appareils cibles.

  6. Entrez le message que l'utilisateur recevra sous la forme d'un message de notification Push.

  7. Cliquez sur Send Notification. Chaque appareil doté d'une inscription avec la balise de nom d'utilisateur correspondante reçoit la notification Push.

Étapes suivantes

Dans ce tutoriel, vous avez appris à envoyer des notifications Push à des utilisateurs spécifiques ayant des balises associées à leurs enregistrements. Pour savoir comment envoyer des notifications basées sur l’emplacement, passez au tutoriel suivant :