Tutoriel : Envoyer des notifications Push vers des utilisateurs spécifiques à l’aide d’Azure Notification Hubs
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 la rubrique d’aide Inscription auprès du serveur principal de votre application.
Dans ce tutoriel, vous effectuez les étapes suivantes :
- Création du projet WebAPI
- Authentification des clients sur le serveur principal WebAPI
- Inscription aux notifications à l’aide du serveur principal WebAPI
- Envoyer des notifications depuis le serveur principal WebAPI
- Publication du nouveau serveur principal WebAPI
- Modification de votre application iOS
- Test de l’application
Prérequis
Ce didacticiel repose sur l'hypothèse que vous avez créé et configuré votre hub de notification comme décrit dans Envoyer des notification Push à des applications iOS avec Azure Notification Hubs. Ce didacticiel est également un prérequis pour le didacticiel sur les notifications Push sécurisées (iOS) . Si vous souhaitez utiliser Mobile Apps comme service principal, voir l’article Mobile Apps concernant la prise en main des notifications Push.
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.
Notes
Assurez-vous que le Kit de développement logiciel (SDK) Azure Visual Studio est installé, pour le déploiement du site web.
Démarrez Visual Studio ou Visual Studio Express.
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é.
Dans Visual Studio, dans le menu Fichier, sélectionnez Nouveau>Projet.
Entrez API web dans le champ de recherche.
Sélectionnez le modèle de projet API web ASP.NET Core, puis Suivant.
Dans la boîte de dialogue Configurer votre nouveau projet, nommez le projet AppBackend, puis sélectionnez Suivant.
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
- Supprimez les fichiers d’exemple WeatherForecast.cs et Controllers/WeatherForecastController.cs du nouveau projet AppBackend.
- Ouvrez Properties\launchSettings.json.
- 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.
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.
Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet AppBackend, puis sélectionnez Ajouter et Classe.
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.
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;
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.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());
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>"
.
Dans l’Explorateur de solutions, cliquez avec le bouton droit sur le projet AppBackend, puis sélectionnez Gérer les packages NuGet.
Dans le volet gauche, sélectionnez En ligne puis tapez Microsoft.Azure.NotificationHubs dans la zone Recherche.
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.
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.
Dans Notifications.cs, ajoutez l’instruction
using
suivante en haut du fichier :using Microsoft.Azure.NotificationHubs;
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.
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.
Sélectionnez Contrôleur API - Vide, puis Ajouter.
Dans la boîte Nom du contrôleur, tapez RegisterController pour nommer la nouvelle classe, puis sélectionnez Ajouter.
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;
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()); } }
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.
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.
Dans NotificationsController.cs, ajoutez les instructions
using
suivantes :using AppBackend.Models; using System.Threading.Tasks; using System.Web;
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 deto_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); }
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.
Cliquez avec le bouton droit sur le projet AppBackend, puis sélectionnez Publier.
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.
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.
Sélectionnez Create (Créer).
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.
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://<nom_application>.azurewebsites.net.
Modification de votre application iOS
Ouvrez l’application en mode page unique que vous avez créée dans le tutoriel Envoyer des notifications Push vers des applications iOS à l’aide d’Azure Notification Hubs.
Notes
Cette section suppose que vous avez configuré votre projet avec un nom d’organisation vide. Si ce n’est pas le cas, ajoutez le nom de votre organisation à tous les noms de classe.
Dans le fichier
Main.storyboard
, ajoutez les composants indiqués dans la capture d’écran de la bibliothèque d’objets.Nom d’utilisateur : champ UITextField avec du texte d’espace réservé, Entrer le nom d’utilisateur, juste en dessous de l’étiquette des résultats d’envoi et entre les marges gauche et droite, en dessous de l’étiquette des résultats d’envoi.
Mot de passe : champ UITextField avec du texte d’espace réservé, Entrer le mot de passe, juste en dessous du champ de texte du nom d’utilisateur et entre les marges gauche et droite, en dessous du champ de texte du nom d’utilisateur. Cochez l'option Sécuriser l'entrée de texte dans l'inspecteur d'attributs sous Touche Retour.
Connexion : un UIButton étiqueté immédiatement en dessous du champ de texte du mot de passe ; décochez l’option Activé dans l’inspecteur d’attributs, sous Contrôle-Contenu
WNS : étiquette et commutateur pour activer l’envoi de la notification du service de notification Windows, si elle a été configurée sur le hub. Consultez le didacticiel Prise en main de Windows.
GCM : étiquette et commutateur pour activer l’envoi de la notification à Google Cloud Messaging, si elle a été configurée sur le hub. Consultez le didacticiel Prise en main d'Android .
APNS : étiquette et commutateur pour activer l’envoi de la notification au service de notification de la plateforme Apple.
Nom d'utilisateur du destinataire: champ UITextField avec du texte d'espace réservé, Balise du nom d'utilisateur du destinataire, juste en dessous de l'étiquette GCM et entre les marges gauche et droite, en dessous de l'étiquette GCM.
Certains composants ont été ajoutés au tutoriel Envoyer des notifications Push à des applications iOS avec Azure Notification Hubs.
Faites glisser les composants de l’affichage vers
ViewController.h
en maintenant la touche Ctrl enfoncée, puis ajoutez ces nouvelles sorties :@property (weak, nonatomic) IBOutlet UITextField *UsernameField; @property (weak, nonatomic) IBOutlet UITextField *PasswordField; @property (weak, nonatomic) IBOutlet UITextField *RecipientField; @property (weak, nonatomic) IBOutlet UITextField *NotificationField; // Used to enable the buttons on the UI @property (weak, nonatomic) IBOutlet UIButton *LogInButton; @property (weak, nonatomic) IBOutlet UIButton *SendNotificationButton; // Used to enabled sending notifications across platforms @property (weak, nonatomic) IBOutlet UISwitch *WNSSwitch; @property (weak, nonatomic) IBOutlet UISwitch *GCMSwitch; @property (weak, nonatomic) IBOutlet UISwitch *APNSSwitch; - (IBAction)LogInAction:(id)sender;
Dans
ViewController.h
, ajoutez le code#define
suivant après vos instructions d’importation. Remplacez l’espace réservé<Your backend endpoint>
par l’URL de destination que vous avez utilisée pour déployer votre serveur principal d’application dans la section précédente. Par exemple,http://your_backend.azurewebsites.net
:#define BACKEND_ENDPOINT @"<Your backend endpoint>"
Dans votre projet, créez une classe Cocoa Touch nommée
RegisterClient
pour communiquer avec le serveur principal ASP.NET que vous avez créé. Créez la classe en héritant deNSObject
. Ajoutez ensuite le code suivant dansRegisterClient.h
:@interface RegisterClient : NSObject @property (strong, nonatomic) NSString* authenticationHeader; -(void) registerWithDeviceToken:(NSData*)token tags:(NSSet*)tags andCompletion:(void(^)(NSError*))completion; -(instancetype) initWithEndpoint:(NSString*)Endpoint; @end
Dans
RegisterClient.m
, mettez à jour la section@interface
:@interface RegisterClient () @property (strong, nonatomic) NSURLSession* session; @property (strong, nonatomic) NSURLSession* endpoint; -(void) tryToRegisterWithDeviceToken:(NSData*)token tags:(NSSet*)tags retry:(BOOL)retry andCompletion:(void(^)(NSError*))completion; -(void) retrieveOrRequestRegistrationIdWithDeviceToken:(NSString*)token completion:(void(^)(NSString*, NSError*))completion; -(void) upsertRegistrationWithRegistrationId:(NSString*)registrationId deviceToken:(NSString*)token tags:(NSSet*)tags andCompletion:(void(^)(NSURLResponse*, NSError*))completion; @end
Remplacez la section
@implementation
dans RegisterClient.m par le code suivant :@implementation RegisterClient // Globals used by RegisterClient NSString *const RegistrationIdLocalStorageKey = @"RegistrationId"; -(instancetype) initWithEndpoint:(NSString*)Endpoint { self = [super init]; if (self) { NSURLSessionConfiguration* config = [NSURLSessionConfiguration defaultSessionConfiguration]; _session = [NSURLSession sessionWithConfiguration:config delegate:nil delegateQueue:nil]; _endpoint = Endpoint; } return self; } -(void) registerWithDeviceToken:(NSData*)token tags:(NSSet*)tags andCompletion:(void(^)(NSError*))completion { [self tryToRegisterWithDeviceToken:token tags:tags retry:YES andCompletion:completion]; } -(void) tryToRegisterWithDeviceToken:(NSData*)token tags:(NSSet*)tags retry:(BOOL)retry andCompletion:(void(^)(NSError*))completion { NSSet* tagsSet = tags?tags:[[NSSet alloc] init]; NSString *deviceTokenString = [[token description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]]; deviceTokenString = [[deviceTokenString stringByReplacingOccurrencesOfString:@" " withString:@""] uppercaseString]; [self retrieveOrRequestRegistrationIdWithDeviceToken: deviceTokenString completion:^(NSString* registrationId, NSError *error) { NSLog(@"regId: %@", registrationId); if (error) { completion(error); return; } [self upsertRegistrationWithRegistrationId:registrationId deviceToken:deviceTokenString tags:tagsSet andCompletion:^(NSURLResponse * response, NSError *error) { if (error) { completion(error); return; } NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; if (httpResponse.statusCode == 200) { completion(nil); } else if (httpResponse.statusCode == 410 && retry) { [self tryToRegisterWithDeviceToken:token tags:tags retry:NO andCompletion:completion]; } else { NSLog(@"Registration error with response status: %ld", (long)httpResponse.statusCode); completion([NSError errorWithDomain:@"Registration" code:httpResponse.statusCode userInfo:nil]); } }]; }]; } -(void) upsertRegistrationWithRegistrationId:(NSString*)registrationId deviceToken:(NSData*)token tags:(NSSet*)tags andCompletion:(void(^)(NSURLResponse*, NSError*))completion { NSDictionary* deviceRegistration = @{@"Platform" : @"apns", @"Handle": token, @"Tags": [tags allObjects]}; NSData* jsonData = [NSJSONSerialization dataWithJSONObject:deviceRegistration options:NSJSONWritingPrettyPrinted error:nil]; NSLog(@"JSON registration: %@", [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]); NSString* endpoint = [NSString stringWithFormat:@"%@/api/register/%@", _endpoint, registrationId]; NSURL* requestURL = [NSURL URLWithString:endpoint]; NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestURL]; [request setHTTPMethod:@"PUT"]; [request setHTTPBody:jsonData]; NSString* authorizationHeaderValue = [NSString stringWithFormat:@"Basic %@", self.authenticationHeader]; [request setValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; NSURLSessionDataTask* dataTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { if (!error) { completion(response, error); } else { NSLog(@"Error request: %@", error); completion(nil, error); } }]; [dataTask resume]; } -(void) retrieveOrRequestRegistrationIdWithDeviceToken:(NSString*)token completion:(void(^)(NSString*, NSError*))completion { NSString* registrationId = [[NSUserDefaults standardUserDefaults] objectForKey:RegistrationIdLocalStorageKey]; if (registrationId) { completion(registrationId, nil); return; } // request new one & save NSURL* requestURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/api/register?handle=%@", _endpoint, token]]; NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestURL]; [request setHTTPMethod:@"POST"]; NSString* authorizationHeaderValue = [NSString stringWithFormat:@"Basic %@", self.authenticationHeader]; [request setValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"]; NSURLSessionDataTask* dataTask = [self.session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response; if (!error && httpResponse.statusCode == 200) { NSString* registrationId = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; // remove quotes registrationId = [registrationId substringWithRange:NSMakeRange(1, [registrationId length]-2)]; [[NSUserDefaults standardUserDefaults] setObject:registrationId forKey:RegistrationIdLocalStorageKey]; [[NSUserDefaults standardUserDefaults] synchronize]; completion(registrationId, nil); } else { NSLog(@"Error status: %ld, request: %@", (long)httpResponse.statusCode, error); if (error) completion(nil, error); else { completion(nil, [NSError errorWithDomain:@"Registration" code:httpResponse.statusCode userInfo:nil]); } } }]; [dataTask resume]; } @end
Ce code implémente la logique expliquée dans l'article Inscription auprès du serveur principal de votre application , et utilise NSURLSession pour passer des appels REST à votre serveur principal d'application et NSUserDefaults pour stocker en local la valeur registrationId renvoyée par le concentrateur de notification.
Cette classe a besoin que sa propriété
authorizationHeader
soit définie afin de fonctionner correctement. Cette propriété est définie par la classeViewController
après la connexion.Dans
ViewController.h
, ajoutez une instruction#import
pourRegisterClient.h
. Ensuite, ajoutez une déclaration pour le jeton de l'appareil et faites référence à une instanceRegisterClient
dans la section@interface
:#import "RegisterClient.h" @property (strong, nonatomic) NSData* deviceToken; @property (strong, nonatomic) RegisterClient* registerClient;
Dans ViewController.m, ajoutez une déclaration de méthode privée dans la section
@interface
:@interface ViewController () <UITextFieldDelegate, NSURLConnectionDataDelegate, NSXMLParserDelegate> // create the Authorization header to perform Basic authentication with your app back-end -(void) createAndSetAuthenticationHeaderWithUsername:(NSString*)username AndPassword:(NSString*)password; @end
Notes
L’extrait de code suivant n’étant pas un schéma d’authentification sécurisé, vous devez remplacer l’implémentation de
createAndSetAuthenticationHeaderWithUsername:AndPassword:
par votre mécanisme d’authentification spécifique qui génère un jeton d’authentification devant être consommé par la classe client du registre, par exemple, OAuth, Active Directory.Ensuite, dans la section
@implementation
deViewController.m
, ajoutez le code suivant qui ajoute l'implémentation pour la définition du jeton de l'appareil et de l'en-tête de l'authentification.-(void) setDeviceToken: (NSData*) deviceToken { _deviceToken = deviceToken; self.LogInButton.enabled = YES; } -(void) createAndSetAuthenticationHeaderWithUsername:(NSString*)username AndPassword:(NSString*)password; { NSString* headerValue = [NSString stringWithFormat:@"%@:%@", username, password]; NSData* encodedData = [[headerValue dataUsingEncoding:NSUTF8StringEncoding] base64EncodedDataWithOptions:NSDataBase64EncodingEndLineWithCarriageReturn]; self.registerClient.authenticationHeader = [[NSString alloc] initWithData:encodedData encoding:NSUTF8StringEncoding]; } -(BOOL)textFieldShouldReturn:(UITextField *)textField { [textField resignFirstResponder]; return YES; }
Remarquez la façon dont le jeton de l’appareil active le bouton Connexion. Ceci est dû au fait que dans le cadre de l’action de connexion, le contrôleur d’affichage s’inscrit aux notifications Push auprès du serveur principal d’application. Vous ne voulez pas que l’action Se connecter soit accessible tant que le jeton de l’appareil n’a pas été correctement configuré. Vous pouvez découpler la connexion de l’inscription aux notifications Push dans la mesure où la connexion se produit avant l’inscription.
Dans ViewController.m, utilisez les extraits de code suivants pour implémenter la méthode d'action de votre bouton Connexion et une méthode pour envoyer le message de notification à l'aide du serveur principal ASP.NET.
- (IBAction)LogInAction:(id)sender { // create authentication header and set it in register client NSString* username = self.UsernameField.text; NSString* password = self.PasswordField.text; [self createAndSetAuthenticationHeaderWithUsername:username AndPassword:password]; __weak ViewController* selfie = self; [self.registerClient registerWithDeviceToken:self.deviceToken tags:nil andCompletion:^(NSError* error) { if (!error) { dispatch_async(dispatch_get_main_queue(), ^{ selfie.SendNotificationButton.enabled = YES; [self MessageBox:@"Success" message:@"Registered successfully!"]; }); } }]; } - (void)SendNotificationASPNETBackend:(NSString*)pns UsernameTag:(NSString*)usernameTag Message:(NSString*)message { NSURLSession* session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:nil delegateQueue:nil]; // Pass the pns and username tag as parameters with the REST URL to the ASP.NET backend NSURL* requestURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@/api/notifications?pns=%@&to_tag=%@", BACKEND_ENDPOINT, pns, usernameTag]]; NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:requestURL]; [request setHTTPMethod:@"POST"]; // Get the mock authenticationheader from the register client NSString* authorizationHeaderValue = [NSString stringWithFormat:@"Basic %@", self.registerClient.authenticationHeader]; [request setValue:authorizationHeaderValue forHTTPHeaderField:@"Authorization"]; //Add the notification message body [request setValue:@"application/json;charset=utf-8" forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:[message dataUsingEncoding:NSUTF8StringEncoding]]; // Execute the send notification REST API on the ASP.NET Backend NSURLSessionDataTask* dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*) response; if (error || httpResponse.statusCode != 200) { NSString* status = [NSString stringWithFormat:@"Error Status for %@: %d\nError: %@\n", pns, httpResponse.statusCode, error]; dispatch_async(dispatch_get_main_queue(), ^{ // Append text because all 3 PNS calls may also have information to view [self.sendResults setText:[self.sendResults.text stringByAppendingString:status]]; }); NSLog(status); } if (data != NULL) { xmlParser = [[NSXMLParser alloc] initWithData:data]; [xmlParser setDelegate:self]; [xmlParser parse]; } }]; [dataTask resume]; }
Mettez à jour l'action du bouton Envoyer une notification pour utiliser le serveur principal ASP.NET et effectuer l'envoi vers n'importe quel PNS activé par un commutateur.
- (IBAction)SendNotificationMessage:(id)sender { //[self SendNotificationRESTAPI]; [self SendToEnabledPlatforms]; } -(void)SendToEnabledPlatforms { NSString* json = [NSString stringWithFormat:@"\"%@\"",self.notificationMessage.text]; [self.sendResults setText:@""]; if ([self.WNSSwitch isOn]) [self SendNotificationASPNETBackend:@"wns" UsernameTag:self.RecipientField.text Message:json]; if ([self.GCMSwitch isOn]) [self SendNotificationASPNETBackend:@"gcm" UsernameTag:self.RecipientField.text Message:json]; if ([self.APNSSwitch isOn]) [self SendNotificationASPNETBackend:@"apns" UsernameTag:self.RecipientField.text Message:json]; }
Dans la fonction
ViewDidLoad
, ajoutez ce qui suit pour instancier l’instance deRegisterClient
et définir le délégué pour vos champs de texte.self.UsernameField.delegate = self; self.PasswordField.delegate = self; self.RecipientField.delegate = self; self.registerClient = [[RegisterClient alloc] initWithEndpoint:BACKEND_ENDPOINT];
À présent, dans
AppDelegate.m
, supprimez tout le contenu de la méthodeapplication:didRegisterForPushNotificationWithDeviceToken:
et remplacez-le par ce qui suit (pour que le contrôleur d’affichage contienne le dernier jeton de l’appareil extrait d’APNs) :// Add import to the top of the file #import "ViewController.h" - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { ViewController* rvc = (ViewController*) self.window.rootViewController; rvc.deviceToken = deviceToken; }
Enfin, assurez-vous qu’
AppDelegate.m
contient la méthode suivante :- (void)application:(UIApplication *)application didReceiveRemoteNotification: (NSDictionary *)userInfo { NSLog(@"%@", userInfo); [self MessageBox:@"Notification" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"]]; }
Test de l’application
Dans XCode, exécutez l’application sur un appareil iOS physique (les notifications Push ne fonctionnent pas dans le simulateur).
Dans l'interface utilisateur de l'application iOS, entrez la même valeur pour le nom d'utilisateur et le mot de passe. Cliquez ensuite sur Log In.
Une fenêtre contextuelle doit s’afficher pour vous informer que l’inscription a abouti. Cliquez sur OK.
Dans le champ de texte *Balise de nom d’utilisateur du destinataire , entrez la balise de nom d’utilisateur utilisée lors de l’enregistrement sur un autre appareil.
Entrez un message de notification et cliquez sur Envoyer une notification. Seuls les appareils qui disposent d'un enregistrement avec la balise de nom d'utilisateur du destinataire reçoivent le message de notification. Il n'est envoyé qu'à ces utilisateurs.
É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 :