Tutorial: Senden von Pushbenachrichtigungen an bestimmte Benutzer mit Azure Notification Hubs
Ein ASP.NET WebAPI-Back-End wird verwendet, um Clients zu authentifizieren. Zum Authentifizieren von Clients und Generieren von Benachrichtigungen wird ein ASP.NET WebAPI-Back-End verwendet, wie im Thema Registrieren von App-Back-End aus gezeigt.
In diesem Tutorial führen Sie die folgenden Schritte aus:
- Erstellen des WebAPI-Projekts
- Authentifizieren von Clients beim WebAPI-Back-End
- Registrieren für Benachrichtigungen unter Verwendung des WebAPI-Back-Ends
- Senden von Benachrichtigungen über das WebAPI-Back-End
- Veröffentlichen des neuen WebAPI-Back-Ends
- Ändern der iOS-App
- Testen der Anwendung
Voraussetzungen
In diesem Tutorial wird davon ausgegangen, dass Sie Ihren Notification Hub wie unter Tutorial: Senden von Pushbenachrichtigungen an iOS-Apps mit Azure Notification Hubs beschrieben erstellt und konfiguriert haben. Dieses Lernprogramm ist außerdem die Voraussetzung für das Lernprogramm Sichere Pushbenachrichtigungen (iOS) . Wenn Sie Mobile Apps als Back-End-Dienst verwenden möchten, lesen Sie Mobile Apps: Erste Schritte mit Push.
Erstellen des WebAPI-Projekts
In den folgenden Abschnitten wird die Erstellung eines neuen ASP.NET-WebAPI-Back-Ends erläutert. Dieser Prozess hat drei Hauptfunktionen:
- Authentifizieren von Clients: Sie fügen einen Meldungshandler hinzu, um Clientanforderungen zu authentifizieren und den Benutzer der Anforderung zuzuordnen.
- Registrieren für Benachrichtigungen unter Verwendung des WebAPI-Back-Ends: Sie fügen einen Controller hinzu, um neue Registrierungen für ein Clientgerät zum Empfangen von Benachrichtigungen zu verarbeiten. Der authentifizierte Benutzername wird der Registrierung automatisch als Tag hinzugefügt.
- Senden von Benachrichtigungen an Clients: Sie fügen einen Controller hinzu, um Benutzern die Möglichkeit zu geben, einen sicheren Pushvorgang an Geräte und Clients auszulösen, die dem Tag zugeordnet sind.
Gehen Sie zum Erstellen des neuen ASP.NET Core 6.0-Web-API-Back-Ends wie folgt vor:
Um dies zu überprüfen, starten Sie Visual Studio. Wählen Sie im Menü Extras die Option Erweiterungen und Updates aus. Suchen Sie in Ihrer Version von Visual Studio nach NuGet-Paket-Manager, und vergewissern Sie sich, dass Sie über die neueste Version verfügen. Deinstallieren Sie andernfalls Ihre Version, und installieren Sie den NuGet-Paket-Manager erneut.
Hinweis
Stellen Sie sicher, dass Sie das Visual Studio Azure SDK für die Websitebereitstellung installiert haben.
Starten Sie Visual Studio oder Visual Studio Express.
Wählen Sie Server-Explorer aus, und melden Sie sich bei Ihrem Azure-Konto an. Zur Erstellung der Websiteressourcen für Ihr Konto müssen Sie angemeldet sein.
Wählen Sie in Visual Studio im Menü Datei die Optionen Neu>Projekt aus.
Geben Sie Web-API in das Suchfeld ein.
Wählen Sie die Projektvorlage ASP.NET Core-Web-API und dann Weiter aus.
Geben Sie im Dialogfeld Neues Projekt konfigurieren dem Projekt den Namen AppBackend, und wählen Sie dann Weiter aus.
Im Dialogfeld Zusätzliche Informationen:
- Vergewissern Sie sich, dass das Framework auf .NET 6.0 (Langfristiger Support) festgelegt ist.
- Vergewissern Sie sich, dass das Kontrollkästchen Controller verwenden (zur Verwendung minimaler APIs deaktivieren) aktiviert ist.
- Deaktivieren Sie OpenAPI-Unterstützung aktivieren.
- Klicken Sie auf Erstellen.
Entfernen der WeatherForecast-Vorlagendateien
- Entfernen Sie die Beispieldateien WeatherForecast.cs und "Controllers/WeatherForecastController.cs aus dem neuen AppBackend-Projekt.
- Öffnen Sie Properties\launchSettings.json.
- Ändern Sie launchUrl-Eigenschaften von wetterforcast in appbackend.
Wählen Sie im Fenster Microsoft Azure-Web-App konfigurieren ein Abonnement aus, und führen Sie anschließend in der Liste App Service-Plan eine der folgenden Aktionen aus:
- Wählen Sie einen bereits erstellten Azure App Service-Plan aus.
- Wählen Sie Einen neuen App Services-Plan erstellen aus, und erstellen Sie einen neuen Plan.
Sie benötigen für dieses Lernprogramm keine Datenbank. Wählen Sie nach der Wahl Ihres App Service-Plans OK aus, um das Projekt zu erstellen.
Wird diese Seite zum Konfigurieren des App Service-Plans nicht angezeigt, fahren Sie mit dem Tutorial fort. Sie können ihn später beim Veröffentlichen der App konfigurieren.
Authentifizieren von Clients beim WebAPI-Back-End
In diesem Abschnitt erstellen Sie für das neue Back-End eine neue Meldungshandlerklasse namens AuthenticationTestHandler. Diese Klasse wird von DelegatingHandler abgeleitet und als Meldungshandler hinzugefügt, damit alle beim Back-End eingehenden Anforderungen verarbeitet werden können.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt AppBackend, und wählen Sie Hinzufügen und anschließend Klasse aus.
Geben Sie der neuen Klasse den Namen AuthenticationTestHandler.cs, und wählen Sie Hinzufügen aus, um die Klasse zu generieren. Mit dieser Klasse werden Benutzer der Einfachheit halber unter Verwendung der Standardauthentifizierung authentifiziert. Ihre App kann ein beliebiges Authentifizierungsschema verwenden.
Fügen Sie in der Datei "AuthenticationTestHandler.cs" die folgenden
using
-Anweisungen hinzu:using System.Net.Http; using System.Threading; using System.Security.Principal; using System.Net; using System.Text; using System.Threading.Tasks;
Ersetzen Sie in der Datei „AuthenticationTestHandler.cs“ die Definition der Klasse
AuthenticationTestHandler
durch den folgenden Code:Der Handler autorisiert die Anforderung, wenn die folgenden drei Bedingungen erfüllt sind:
- Die Anforderung enthält einen Autorisierungsheader.
- Für die Anforderung wird die Standardauthentifizierung verwendet.
- Bei der Benutzernamen-Zeichenfolge und der Kennwortzeichenfolge handelt es sich um die gleiche Zeichenfolge.
Andernfalls wird die Anforderung abgelehnt. Diese Authentifizierung ist keine echte Vorgehensweise zur Authentifizierung und Autorisierung. Hierbei handelt es sich lediglich um ein einfaches Beispiel für dieses Tutorial.
Wenn die Anforderungsnachricht von
AuthenticationTestHandler
authentifiziert und autorisiert wurde, wird der Benutzer der Standardauthentifizierung an die aktuelle Anforderung in HttpContext angefügt. Die Benutzerinformationen in „HttpContext“ werden später von einem anderen Controller (RegisterController) verwendet, um der Registrierungsanforderung für die Benachrichtigung ein Tag hinzuzufügen.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; } }
Hinweis
Sicherheitshinweis: Die Klasse
AuthenticationTestHandler
ermöglicht keine wirkliche Authentifizierung. Sie wird nur verwendet, um eine Standardauthentifizierung zu imitieren, und ist nicht sicher. Sie müssen einen sicheren Authentifizierungsmechanismus in Ihren Produktionsanwendungen und -diensten implementieren.Fügen Sie am Ende der
Register
-Methode in der Datei Program.cs den folgenden Code hinzu, um den Meldungshandler zu registrieren:config.MessageHandlers.Add(new AuthenticationTestHandler());
Speichern Sie die Änderungen.
Registrieren für Benachrichtigungen unter Verwendung des WebAPI-Back-Ends
In diesem Abschnitt wird dem WebAPI-Back-End ein neuer Controller hinzugefügt, um Anforderungen zum Registrieren eines Benutzers und eines Geräts für Benachrichtigungen unter Verwendung der Clientbibliothek für Notification Hubs zu verarbeiten. Der Controller fügt ein Benutzertag für den Benutzer hinzu, der durch AuthenticationTestHandler
authentifiziert und an „HttpContext“ angefügt wurde. Die Markierung hat das Zeichenfolgenformat "username:<actual username>"
.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Projekt AppBackend, und wählen Sie dann NuGet-Pakete verwalten aus.
Wählen Sie im linken Bereich Online aus, und geben Sie dann im Feld Suche die Zeichenfolge Microsoft.Azure.NotificationHubs ein.
Wählen Sie in der Ergebnisliste die Option Microsoft Azure Notification Hubs und anschließend Installieren aus. Schließen Sie die Installation ab, und schließen Sie dann das Fenster des NuGet-Paket-Managers.
Dadurch wird mithilfe des Microsoft.Azure.NotificationHubs-NuGet-Pakets ein Verweis auf das Azure Notification Hubs-SDK hinzugefügt.
Erstellen Sie eine neue Klassendatei, die die Verbindung mit dem Notification Hub darstellt, der zum Senden von Benachrichtigungen verwendet wird. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Modelle, und wählen Sie dann Hinzufügen und anschließend Klasse aus. Nennen Sie die neue Klasse Notifications.cs, und wählen Sie dann Hinzufügen aus, um die Klasse zu generieren.
Fügen Sie die folgende
using
-Anweisung am Anfang der Datei "Notifications.cs" hinzu:using Microsoft.Azure.NotificationHubs;
Ersetzen Sie die Definition der Klasse
Notifications
durch den folgenden Code und die beiden Platzhalter durch die Verbindungszeichenfolge (mit Vollzugriff) für Ihren Notification Hub bzw. durch den Namen des Hubs (verfügbar im Azure-Portal):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>"); } }
Wichtig
Geben Sie für den Hub den Namen und einen Wert für DefaultFullSharedAccessSignature ein, bevor Sie fortfahren.
Erstellen Sie als Nächstes einen neuen Controller namens RegisterController. Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Ordner Controller, und wählen Sie dann Hinzufügen und Controller aus.
Wählen Sie API-Controller – Leer und anschließend Hinzufügen aus.
Geben Sie im Feld Controllername die Zeichenfolge RegisterController ein, um die neue Klasse zu benennen, und wählen Sie anschließend Hinzufügen aus.
Fügen Sie in der Datei "RegisterController.cs" die folgenden
using
-Anweisungen hinzu:using Microsoft.Azure.NotificationHubs; using Microsoft.Azure.NotificationHubs.Messaging; using AppBackend.Models; using System.Threading.Tasks; using System.Web;
Fügen Sie innerhalb der
RegisterController
-Klassendefinition den folgenden Code hinzu. Mit diesem Code fügen Sie ein Benutzertag für den Benutzer hinzu, der HttpContext angefügt ist. Der Benutzer wurde mit dem von Ihnen hinzugefügten NachrichtenfilterAuthenticationTestHandler
authentifiziert und HttpContext angefügt. Sie können auch optionale Überprüfungen hinzufügen, um zu überprüfen, dass der Benutzer die richtigen Berechtigungen besitzt, um sich für die angeforderten Tags zu registrieren.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()); } }
Speichern Sie die Änderungen.
Senden von Benachrichtigungen über das WebAPI-Back-End
In diesem Abschnitt wird ein neuer Controller hinzugefügt, der Clientgeräten das Senden einer Benachrichtigung ermöglicht. Die Benachrichtigung basiert auf dem Benutzernamentag, das die Azure Notification Hubs .NET-Bibliothek des ASP.NET WebAPI-Back-Ends verwendet.
Erstellen Sie einen weiteren neuen Domänencontroller namens NotificationsController. Verwenden Sie dazu die gleiche Vorgehensweise wie bei der Erstellung von RegisterController im vorherigen Abschnitt.
Fügen Sie in der Datei "NotificationsController.cs" die folgenden
using
-Anweisungen hinzu:using AppBackend.Models; using System.Threading.Tasks; using System.Web;
Fügen Sie der Klasse NotificationsController die folgende Methode hinzu:
Mit diesem Code wird ein Benachrichtigungstyp gesendet, der auf dem Parameter
pns
des Plattformbenachrichtigungssystems (Plattform Notification System, PNS) basiert. Der Wert vonto_tag
dient zum Festlegen des username -Tags in der Nachricht. Dieses Tag muss mit einem Benutzernamentag einer aktiven Notification Hub-Registrierung übereinstimmen. Die Benachrichtigung wird aus dem Text der POST-Anforderung abgerufen und für den Ziel-PNS formatiert.Abhängig von dem PNS, mit dem Ihre unterstützten Geräte Benachrichtigungen empfangen, werden Benachrichtigungen mit unterschiedlichen Formaten unterstützt. Ein Beispiel: Angenommen, Sie verwenden auf Windows-Geräten eine Popupbenachrichtigung mit WNS, die nicht direkt durch ein anderes PNS unterstützt wird. In diesem Fall muss Ihr Back-End die Benachrichtigung so formatieren, dass sie mit dem PNS der zu unterstützenden Geräte kompatibel ist. Verwenden Sie anschließend die entsprechende Sende-API für die NotificationHubClient-Klasse.
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); }
Drücken Sie F5, um die Anwendung auszuführen und sich zu vergewissern, dass soweit alles funktioniert. Die App öffnet einen Webbrowser und wird auf der Homepage von ASP.NET angezeigt.
Veröffentlichen des neuen WebAPI-Back-Ends
Als Nächstes wird die App auf einer Azure-Website bereitgestellt, damit sie für alle Geräte zur Verfügung steht.
Klicken Sie mit der rechten Maustaste auf das Projekt AppBackend, und wählen Sie Veröffentlichen aus.
Wählen Sie Microsoft Azure App Service als Veröffentlichungsziel und anschließend **Veröffentlichen aus. Das Fenster „App Service erstellen“ wird geöffnet. Hier können Sie alle Azure-Ressourcen erstellen, die zum Ausführen der ASP.NET-Web-App in Azure benötigt werden.
Wählen Sie im Fenster App Service erstellen Ihr Azure-Konto aus. Wählen Sie Typ ändern>Web App aus. Behalten Sie den Standardwert für Web-App-Name bei, und wählen Sie Abonnement, Ressourcengruppe und App Service-Plan aus.
Klicken Sie auf Erstellen.
Notieren Sie sich die Website-URL aus der Zusammenfassung. Diese URL ist später im Tutorial Ihr Back-End-Endpunkt.
Wählen Sie Veröffentlichen.
Nach Abschluss des Assistenten wird die ASP.NET Web-App in Azure veröffentlicht und anschließend im Standardbrowser geöffnet. Ihre Anwendung kann in Azure App Services angezeigt werden.
In der URL wird der von Ihnen angegebene Web-App-Name im Format http://<app_name>.azurewebsites.net verwendet.
Ändern der iOS-App
Öffnen Sie die Einzelseitenansicht-App, die Sie in Tutorial: Senden von Pushbenachrichtigungen an iOS-Apps mit Azure Notification Hubs erstellt haben.
Hinweis
In diesem Abschnitt wird davon ausgegangen, dass Sie Ihr Projekt mit einem leeren Organisationsnamen konfiguriert haben. Falls nicht, stellen Sie allen Klassennamen Ihren Organisationsnamen voran.
Fügen Sie in der Datei
Main.storyboard
die im folgenden Screenshot abgebildeten Komponenten aus der Objektbibliothek hinzu.Benutzername: Ein UITextField mit dem Platzhaltertext Enter Username, direkt unter der Bezeichnung zum Senden der Ergebnisse und durch den linken und rechten Rand und die Anordnung unter der Bezeichnung zum Senden der Ergebnisse beschränkt.
Kennwort: Ein UITextField mit dem Platzhaltertext Enter Password, direkt unter dem Textfeld „Username“ und durch den linken und rechten Rand und die Anordnung unter dem Textfeld „Username“ beschränkt. Aktivieren Sie die Option Secure Text Entry im Attribute Inspector unter Return Key.
Log in: Ein bezeichneter UIButton direkt unter dem Kennwortfeld. Deaktivieren Sie die Option Enabled im Attributes Inspector unter Control-Content.
WNS: Bezeichnung und Switch, um das Senden der Benachrichtigung an den Windows-Benachrichtigungsdienst zu aktivieren, wenn er auf dem Hub eingerichtet wurde. Siehe dazu das Tutorial Erste Schritte für Windows.
GCM: Bezeichnung und Switch, um das Senden der Benachrichtigung an Google Cloud Messaging zu aktivieren, wenn es auf dem Hub eingerichtet wurde. Siehe dazu das Lernprogramm Erste Schritte für Android .
APNS: Bezeichnung und Switch, um das Senden der Benachrichtigung an den Apple Platform Notification Service zu aktivieren.
Recipient Username: ein UITextField mit dem Platzhaltertext Recipient username tag, direkt unter der GCM-Bezeichnung und durch den linken und rechten Rand und die Anordnung unter der GCM-Bezeichnung beschränkt.
In Tutorial: Senden von Pushbenachrichtigungen an iOS-Apps mit Azure Notification Hubs wurden einige Komponenten hinzugefügt.
Ziehen Sie bei gedrückter STRG-Taste die Komponenten in der Ansicht zu
ViewController.h
, und fügen Sie diese neuen Outlets hinzu:@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;
Fügen Sie in
ViewController.h
folgende#define
-Zeile direkt hinter den import-Anweisungen hinzu. Ersetzen Sie den Platzhalter<Your backend endpoint>
durch die Ziel-URL, die Sie im vorherigen Abschnitt zum Bereitstellen Ihres App-Back-Ends verwendet haben. Zum Beispielhttp://your_backend.azurewebsites.net
:#define BACKEND_ENDPOINT @"<Your backend endpoint>"
Erstellen Sie in Ihrem Projekt eine neue „Cocoa Touch“-Klasse mit dem Namen
RegisterClient
als Schnittstelle mit dem erstellten ASP.NET-Back-End. Erstellen Sie die Klasse, die vonNSObject
erbt. Fügen Sie anschließend inRegisterClient.h
den folgenden Code hinzu:@interface RegisterClient : NSObject @property (strong, nonatomic) NSString* authenticationHeader; -(void) registerWithDeviceToken:(NSData*)token tags:(NSSet*)tags andCompletion:(void(^)(NSError*))completion; -(instancetype) initWithEndpoint:(NSString*)Endpoint; @end
Aktualisieren Sie in
RegisterClient.m
den@interface
-Abschnitt:@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
Ersetzen Sie den
@implementation
-Abschnitt in „RegisterClient.m“ durch den folgenden Code:@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
Dieser Code implementiert die im Artikel Registrieren über ein App-Back-End erläuterte Logik unter Verwendung von NSURLSession zum Durchführen von REST-Aufrufen an das App-Back-End und von NSUserDefaults zum lokalen Speichern der vom Notification Hub zurückgegebenen registrationId.
Die
authorizationHeader
-Eigenschaft dieser Klasse muss festgelegt werden, damit die Klasse ordnungsgemäß funktioniert. Diese Eigenschaft wird von derViewController
-Klasse nach der Anmeldung festgelegt.Fügen Sie in
ViewController.h
eine#import
-Anweisung fürRegisterClient.h
hinzu. Fügen Sie dann eine Deklaration für das Gerätetoken und einen Verweis auf eineRegisterClient
-Instanz im@interface
-Abschnitt hinzu:#import "RegisterClient.h" @property (strong, nonatomic) NSData* deviceToken; @property (strong, nonatomic) RegisterClient* registerClient;
Fügen Sie in "ViewController.m" eine private Methodendeklaration im
@interface
-Abschnitt hinzu:@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
Hinweis
Der folgende Codeausschnitt ist kein sicheres Authentifizierungsschema. Sie sollten die Implementierung von
createAndSetAuthenticationHeaderWithUsername:AndPassword:
durch Ihren spezifischen Authentifizierungsmechanismus ersetzen, der ein von der RegisterClient-Klasse verwendetes Authentifizierungstoken generiert, z.B. OAuth, Active Directory.Fügen Sie dann im
@implementation
-Abschnitt vonViewController.m
den folgenden Code ein, der die Implementierung zum Festlegen des Gerätetokens und Authentifizierungsheaders hinzugefügt.-(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; }
Beachten Sie, dass durch Festlegen des Gerätetokens die Schaltfläche Log in (Anmelden) aktiviert wird. Dies liegt daran, dass sich der Ansichtscontroller bei der Anmeldeaktion für Pushbenachrichtigungen beim App-Back-End registriert. Daher soll erst auf die Anmeldeaktion (Log in) zugegriffen werden können, wenn das Gerätetoken ordnungsgemäß eingerichtet wurde. Sie können die Anmeldung von der Pushregistrierung entkoppeln, solange die Anmeldung vor der Registrierung erfolgt.
Verwenden Sie in „ViewController.m“ die folgenden Codeausschnitte, um die Aktionsmethode für die Schaltfläche Log in (Anmelden) und eine Methode zum Senden der Benachrichtigungsmeldung mithilfe des ASP.NET-Back-Ends zu implementieren.
- (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]; }
Aktualisieren Sie die Aktion für die Schaltfläche Send Notification , sodass das ASP.NET-Back-End verwendet wird und der Sendevorgang an ein beliebiges durch einen Switch aktiviertes PNS erfolgt.
- (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]; }
Fügen Sie in der Funktion
ViewDidLoad
Folgendes hinzu, um dieRegisterClient
-Instanz zu instanziieren und den Delegat für Ihre Textfelder festzulegen.self.UsernameField.delegate = self; self.PasswordField.delegate = self; self.RecipientField.delegate = self; self.registerClient = [[RegisterClient alloc] initWithEndpoint:BACKEND_ENDPOINT];
Entfernen Sie jetzt in
AppDelegate.m
den gesamten Inhalt derapplication:didRegisterForPushNotificationWithDeviceToken:
-Methode, und ersetzen Sie ihn durch Folgendes, um sicherzustellen, dass der Ansichtscontroller das neueste Gerätetoken aus APNs abgerufen hat:// 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; }
Stellen Sie schließlich sicher, dass
AppDelegate.m
die folgende Methode enthält:- (void)application:(UIApplication *)application didReceiveRemoteNotification: (NSDictionary *)userInfo { NSLog(@"%@", userInfo); [self MessageBox:@"Notification" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"]]; }
Testen der Anwendung
Unter XCode führen Sie die App auf einem physischen iOS-Gerät aus (im Simulator funktionieren Pushbenachrichtigungen nicht).
Geben Sie in der Benutzeroberfläche der iOS-App denselben Wert für den Benutzernamen und das Kennwort ein. Klicken Sie dann auf Log in (Anmelden).
Ein Popupfenster sollte angezeigt werden, in dem Sie über eine erfolgreiche Registrierung informiert werden. Klicken Sie auf OK.
Geben Sie im TextfeldRecipient username tag das Benutzernamenstag ein, das bei der Anmeldung von einem anderen Gerät verwendet wird.
Geben Sie eine Benachrichtigungsmeldung ein, und klicken Sie auf Send Notification. Die Benachrichtigungsmeldung wird nur auf den Geräten empfangen, die für das Empfänger-Benutzernamenstag registriert sind. Sie wird nur an diese Benutzer gesendet.
Nächste Schritte
In diesem Tutorial haben Sie gelernt, wie Sie Pushbenachrichtigungen an bestimmte Benutzer senden, deren Registrierungen Tags zugeordnet sind. Um zu erfahren, wie Sie standortbasierte Pushbenachrichtigungen senden, fahren Sie mit dem folgenden Tutorial fort: