Kurz: Odesílání nabízených oznámení konkrétním uživatelům pomocí Azure Notification Hubs
V tomto kurzu se dozvíte, jak pomocí služby Azure Notification Hubs posílat nabízená oznámení konkrétním uživatelům aplikace na konkrétním zařízení. Back-end ASP.NET WebAPI se používá k ověřování klientů a generování oznámení, jak je znázorněno v tématu s pokyny k registraci z back-endu vaší aplikace.
V tomto kurzu provedete následující kroky:
- Vytvoření projektu WebAPI
- Ověřování klientů v back-endu WebAPI
- Registrace k oznámením pomocí back-endu WebAPI
- Odesílání oznámení z back-endu WebAPI
- Publikování nového back-endu WebAPI
- Úprava aplikace pro iOS
- Testování aplikace
Požadavky
V tomto kurzu se předpokládá, že jste vytvořili a nakonfigurovali centrum oznámení, jak je popsáno v tématu Odesílání nabízených oznámení do aplikací pro iOS pomocí Azure Notification Hubs. Tento kurz je také předpokladem pro kurz zabezpečeného nabízení (iOS). Pokud chcete jako back-endovou službu používat Mobile Apps, přečtěte si článek Začínáme s nabízenou oznámením Mobile Apps.
Vytvoření projektu WebAPI
Následující části popisují vytvoření nového back-endu ASP.NET WebAPI. Tento proces má tři hlavní účely:
- Ověřování klientů: Přidáte popisovač zprávy, který bude ověřovat požadavky klientů a přiřazovat uživatele k požadavkům.
- Registrace k oznámením pomocí back-endu WebAPI: Přidáte kontroler, který bude zpracovávat nové registrace klientských zařízení k přijímání oznámení. Ověřené uživatelské jméno se automaticky přidá do registrace jako značka.
- Odesílání oznámení klientům: Přidáte kontroler, který uživatelům umožní aktivovat zabezpečené nabízení do zařízení a klientů přidružených ke značce.
Pomocí následujících akcí vytvořte nový back-end webového rozhraní API ASP.NET Core 6.0:
Pokud to chcete zkontrolovat, spusťte sadu Visual Studio. V nabídce Nástroje vyberte Rozšíření a aktualizace. Vyhledejte Správce balíčků NuGet ve vaší verzi sady Visual Studio a ujistěte se, že máte nejnovější verzi. Pokud vaše verze není nejnovější verzí, odinstalujte ji a pak znovu nainstalujte Správce balíčků NuGet.
Poznámka
Ujistěte se, že jste nainstalovali sadu Visual Studio Azure SDK pro nasazení webu.
Spusťte sadu Visual Studio nebo Visual Studio Express.
Vyberte Průzkumník serveru a přihlaste se ke svému účtu Azure. Abyste mohli vytvářet prostředky webu, musíte být přihlášení.
V nabídce Soubor sady Visual Studio vyberte Nový>projekt.
Do vyhledávacího pole zadejte Webové rozhraní API .
Vyberte šablonu projektu webového rozhraní API ASP.NET Core a vyberte Další.
V dialogovém okně Konfigurace nového projektu pojmenujte projekt AppBackend a vyberte Další.
V dialogovém okně Další informace :
- Ověřte, že je rozhraní .NET 6.0 (dlouhodobá podpora).
- Ověřte, že je zaškrtnuté políčko Používat kontrolery (zrušte zaškrtnutí, pokud chcete použít minimální počet rozhraní API).
- Zrušte zaškrtnutí políčka Povolit podporu OpenAPI.
- Vyberte Vytvořit.
Odebrání souborů šablon WeatherForecast
- Z nového projektu AppBackend odeberte ukázkové soubory WeatherForecast.cs a Controllers/WeatherForecastController.cs.
- Otevřete Properties\launchSettings.json.
- Změňte vlastnosti launchUrl z weatherforcast na appbackend.
V okně Konfigurovat webovou aplikaci Microsoft Azure vyberte předplatné a pak v seznamu Plán služby App Service proveďte jednu z následujících akcí:
- Vyberte plán Azure App Service, který jste už vytvořili.
- Vyberte možnost Vytvořit nový plán App Service a pak tento plán vytvořte.
Pro účely tohoto kurzu nepotřebujete databázi. Jakmile vyberete plán služby App Service, výběrem OK vytvořte projekt.
Pokud tuto stránku pro konfiguraci plánu služby App Service nevidíte, pokračujte kurzem. Můžete ho nakonfigurovat při pozdějším publikování aplikace.
Ověřování klientů v back-endu WebAPI
V této části vytvoříte pro nový back-end novou třídu popisovače zprávy AuthenticationTestHandler. Tato třída je odvozená od třídy DelegatingHandler a přidaná jako popisovač zprávy, aby mohla zpracovávat všechny požadavky přicházející na back-end.
V Průzkumníku řešení klikněte pravým tlačítkem na projekt AppBackend, vyberte Přidat a pak vyberte Třída.
Pojmenujte novou třídu AuthenticationTestHandler.cs a pak ji výběrem Přidat vygenerujte. Tato třída bude pro zjednodušení ověřovat uživatele pomocí základního ověřování. Vaše aplikace může používat jakékoli schéma ověřování.
V souboru AuthenticationTestHandler.cs přidejte následující příkazy
using
:using System.Net.Http; using System.Threading; using System.Security.Principal; using System.Net; using System.Text; using System.Threading.Tasks;
V souboru AuthenticationTestHandler.cs nahraďte definici třídy
AuthenticationTestHandler
následujícím kódem:Tato obslužná rutina ověří požadavek při splnění těchto tří podmínek:
- Požadavek obsahuje autorizační hlavičku.
- Požadavek používá základní ověřování.
- Řetězce uživatelského jména a hesla jsou stejné.
Jinak bude požadavek zamítnut. Při tomto ověření se nepoužívá správný přístup k ověřování a autorizaci. Je to jenom jednoduchý příklad pro účely tohoto kurzu.
Pokud třída
AuthenticationTestHandler
ověří a autorizuje zprávu požadavku, uživatel základního ověřování se připojí k aktuálnímu požadavku v objektu HttpContext. Informace o uživateli v objektu HttpContext později použije jiný kontroler (RegisterController) pro přidání značky do požadavku na registraci oznámení.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; } }
Poznámka
Poznámka k zabezpečení: Třída
AuthenticationTestHandler
nezajišťuje skutečné ověřování. Používá se pouze k napodobení základního ověřování a není bezpečná. Ve svých produkčních aplikacích a službách musíte implementovat mechanismus zabezpečeného ověřování.Pokud chcete zaregistrovat obslužnou rutinu zprávy, přidejte do souboru Program.cs na konec
Register
metody následující kód:config.MessageHandlers.Add(new AuthenticationTestHandler());
Uložte provedené změny.
Registrace k oznámením pomocí back-endu WebAPI
V této části přidáte do back-endu WebAPI nový kontroler, který bude zpracovávat požadavky na registraci uživatele a zařízení k oznámením pomocí klientské knihovny pro centra oznámení. Kontroler přidá značku uživatele pro uživatele, který byl ověřen a připojen k objektu HttpContext třídou AuthenticationTestHandler
. Značka bude mít formát řetězce "username:<actual username>"
.
V Průzkumníku řešení klikněte pravým tlačítkem na projekt AppBackend a pak vyberte Spravovat balíčky NuGet.
V levém podokně vyberte Online a pak do pole Hledat zadejte Microsoft.Azure.NotificationHubs.
V seznamu výsledků vyberte Microsoft Azure Notification Hubs a pak vyberte Nainstalovat. Dokončete instalaci a pak zavřete okno Správce balíčků NuGet.
Tato akce přidá referenci na sadu SDK služby Azure Notification Hubs pomocí balíčku NuGet Microsoft.Azure.Notification Hubs.
Vytvořte nový soubor třídy, která představuje propojení s centrem událostí sloužícím k odesílání oznámení. V Průzkumníku řešení klikněte pravým tlačítkem na složku Modely, vyberte Přidat a pak vyberte Třída. Pojmenujte novou třídu Notifications.cs a pak ji výběrem Přidat vygenerujte.
Na začátek souboru Notifications.cs přidejte následující příkaz
using
:using Microsoft.Azure.NotificationHubs;
Nahraďte definici třídy
Notifications
následujícím kódem a nahraďte dva zástupné symboly připojovacím řetězcem (pro úplný přístup) vašeho centra událostí a názvem centra (najdete ho na webu 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>"); } }
Důležité
Než budete pokračovat, zadejte název a defaultFullSharedAccessSignature vašeho centra.
Dále vytvořte nový kontroler RegisterController. V Průzkumníku řešení klikněte pravým tlačítkem na složku Kontrolery, vyberte Přidat a pak vyberte Kontroler.
Vyberte Kontroler rozhraní API – prázdný a pak vyberte Přidat.
Do pole Název kontroleru zadejte RegisterController a pojmenujte tak novou třídu, pak vyberte Přidat.
V souboru RegisterController.cs přidejte následující příkazy
using
:using Microsoft.Azure.NotificationHubs; using Microsoft.Azure.NotificationHubs.Messaging; using AppBackend.Models; using System.Threading.Tasks; using System.Web;
Do definice třídy
RegisterController
přidejte následující kód. V tomto kódu přidáváte značku uživatele pro uživatele, který je připojený k objektu HttpContext. Tento uživatel byl ověřen a připojen k objektu HttpContext filtrem zprávAuthenticationTestHandler
, který jste vytvořili. Můžete také přidat volitelné kontroly pro ověření, že uživatel má práva pro registraci k požadovaným značkám.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()); } }
Uložte provedené změny.
Odesílání oznámení z back-endu WebAPI
V této části přidáte nový kontroler, který zveřejňuje způsob odesílání oznámení klientskými zařízeními. Oznámení je založené na značce uživatelského jména, kterou používá knihovna .NET Notification Hubs v back-endu ASP.NET WebAPI.
Vytvořte další nový kontroler NotificationsController stejným způsobem, kterým jste v předchozí části vytvořili RegisterController.
V souboru NotificationsController.cs přidejte následující příkazy
using
:using AppBackend.Models; using System.Threading.Tasks; using System.Web;
Do třídy NotificationsController přidejte následující metodu:
Tento kód odesílá typ oznámení na základě parametru
pns
systému oznámení platformy. Hodnotato_tag
slouží k nastavení značky username (uživatelské jméno) pro zprávu. Tato značka musí odpovídat značce uživatelského jména aktivní registrace k centru událostí. Zpráva oznámení se přetáhne z textu požadavku POST a naformátuje se pro cílový systém oznámení platformy.V závislosti na systému oznámení platformy, který vaše zařízení používá k přijímání oznámení, jsou podporována oznámení v různých formátech. Například na zařízeních s Windows byste mohli použít informační zprávu pomocí Služby nabízených oznámení Windows, kterou ostatní systémy oznámení platformy přímo nepodporují. V takovém případě musí váš back-end formátovat oznámení na podporované oznámení pro systémy oznámení platformy zařízení, která chcete podporovat. Ve třídě NotificationHubClient pak použijte vhodné rozhraní API pro odesílání.
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); }
Stisknutím klávesy F5 aplikaci spusťte a ověřte, že jste zatím postupovali správně. Aplikace otevře webový prohlížeč a zobrazí se na domovské stránce ASP.NET.
Publikování nového back-endu WebAPI
Dále tuto aplikaci nasadíte na web Azure, aby byla přístupná ze všech zařízení.
Klikněte pravým tlačítkem na projekt AppBackend a vyberte Publikovat.
Jako cíl publikování vyberte Microsoft Azure App Service a pak vyberte \*\*Publikovat. Otevře se okno Vytvořit plán App Service. Tady můžete vytvořit všechny prostředky Azure, které jsou potřeba ke spuštění webové aplikace ASP.NET v Azure.
V okně Vytvořit plán App Service vyberte váš účet Azure. Vyberte Změnit typ>webové aplikace. Ponechejte výchozí Název webové aplikace a vyberte Předplatné, Skupinu prostředků a Plán služby App Service.
Vyberte Vytvořit.
Poznamenejte si vlastnost Adresa URL webu v části Souhrn. Tato adresa URL je váš koncový bod back-endu, který použijete později v tomto kurzu.
Vyberte Publikovat.
Průvodce po dokončení publikuje webovou aplikaci ASP.NET do Azure a pak tuto aplikaci otevře ve výchozím prohlížeči. Vaši aplikaci bude možné zobrazit ve službě Azure App Service.
Adresa URL používá název webové aplikace, který jste zadali dříve, ve formátu http://< app_name.azurewebsites.net>.
Úprava aplikace pro iOS
Otevřete aplikaci jednostránkového zobrazení, kterou jste vytvořili v kurzu Odesílání nabízených oznámení do aplikací pro iOS pomocí Služby Notification Hubs .
Poznámka
V této části se předpokládá, že je váš projekt nakonfigurovaný s prázdným názvem organizace. Pokud ne, předestavte název vaší organizace na všechny názvy tříd.
Main.storyboard
Do souboru přidejte komponenty zobrazené na snímku obrazovky z knihovny objektů.Uživatelské jméno: Pole UITextField se zástupným textem Zadejte uživatelské jméno hned pod popiskem výsledků odeslání a omezené na levý a pravý okraj a pod popiskem odeslat výsledky.
Heslo: Pole UITextField se zástupným textem Zadejte heslo hned pod textovým polem uživatelského jména a omezené na levý a pravý okraj a pod textové pole uživatelského jména. Zaškrtněte možnost Zabezpečené zadávání textu v inspektoru atributů v části Return Key.
Přihlášení: Tlačítko UIbutton označené bezprostředně pod textovým polem hesla a zrušení zaškrtnutí políčka Povoleno v kontrole atributů v části Control-Content
WNS: Popiskem a přepínačem povolíte odesílání oznámení Windows Notification Service, pokud je nastavená v centru. Projděte si kurz windows Začínáme.
GCM: Popiskem a přepnutím povolíte odesílání oznámení do služby Google Cloud Messaging, pokud je nastavené v centru. Podívejte se na kurz k androidu Začínáme.
APNS: Popisky a přepnutím povolíte odesílání oznámení do služby oznámení platformy Apple.
Uživatelské jméno příjemce:A UITextField se zástupným textem, značkou uživatelského jména příjemce, bezprostředně pod popiskem GCM a omezeným na levé a pravé okraje a pod popiskem GCM.
Některé komponenty byly přidány v kurzu Odesílání nabízených oznámení do aplikací pro iOS pomocí služby Azure Notification Hubs .
Stisknutím klávesy Ctrl přetáhněte ze součástí v zobrazení na
ViewController.h
a přidejte tyto nové výstupy:@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;
V
ViewController.h
souboru přidejte#define
následující příkazy za příkazy importu.<Your backend endpoint>
Zástupný symbol nahraďte cílovou adresou URL, kterou jste použili k nasazení back-endu aplikace v předchozí části. Příkladhttp://your_backend.azurewebsites.net
:#define BACKEND_ENDPOINT @"<Your backend endpoint>"
Ve svém projektu vytvořte novou třídu Cocoa Touch s názvem
RegisterClient
pro rozhraní s ASP.NET back-endem, který jste vytvořili. Vytvořte třídu dědící zNSObject
. Pak doRegisterClient.h
pole přidejte následující kód :@interface RegisterClient : NSObject @property (strong, nonatomic) NSString* authenticationHeader; -(void) registerWithDeviceToken:(NSData*)token tags:(NSSet*)tags andCompletion:(void(^)(NSError*))completion; -(instancetype) initWithEndpoint:(NSString*)Endpoint; @end
V části
RegisterClient.m
aktualizujte@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
@implementation
Nahraďte oddíl v RegisterClient.m následujícím kódem:@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
Tento kód implementuje logiku vysvětlenou v článku s pokyny k registraci z back-endu vaší aplikace pomocí NSURLSession k provádění volání REST do back-endu vaší aplikace a NSUserDefaults k místnímu ukládání ID registrace vrácené centrem oznámení.
Tato třída vyžaduje, aby její vlastnost
authorizationHeader
byla nastavena, aby fungovala správně. Tato vlastnost je nastavenaViewController
třídou po přihlášení.V
ViewController.h
souboru přidejte#import
příkaz proRegisterClient.h
. Pak přidejte deklaraci tokenu zařízení a odkaz naRegisterClient
instanci v části@interface
:#import "RegisterClient.h" @property (strong, nonatomic) NSData* deviceToken; @property (strong, nonatomic) RegisterClient* registerClient;
V souboru ViewController.m přidejte deklaraci privátní metody v části
@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
Poznámka
Následující fragment kódu není schématem zabezpečeného
createAndSetAuthenticationHeaderWithUsername:AndPassword:
ověřování. Implementaci byste měli nahradit vaším konkrétním ověřovacím mechanismem, který generuje ověřovací token, který bude využíván třídou klienta register, například OAuth, Active Directory.Pak v
@implementation
částiViewController.m
přidejte následující kód, který přidá implementaci pro nastavení tokenu zařízení a hlavičky ověřování.-(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; }
Všimněte si, jak nastavení tokenu zařízení povolí tlačítko Přihlásit se . Je to proto, že v rámci akce přihlášení se kontroler zobrazení zaregistruje k nabízeným oznámením v back-endu aplikace. Nechcete, aby byla akce Přihlášení přístupná, dokud nebude token zařízení správně nastavený. Přihlášení můžete oddělit od registrace nabízených oznámení, pokud se první z nich stane před druhou registrací.
V souboru ViewController.m použijte následující fragmenty kódu k implementaci metody akce pro tlačítko Přihlásit se a metodu pro odeslání zprávy oznámení pomocí ASP.NET back-endu.
- (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]; }
Aktualizujte akci tlačítka Odeslat oznámení tak, aby používalo back-end ASP.NET a odeslalo ho do libovolného PNS povoleného přepínačem.
- (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]; }
ViewDidLoad
Do funkce přidejte následující příkaz pro vytvoření instance instance a nastavte delegátaRegisterClient
pro vaše textová pole.self.UsernameField.delegate = self; self.PasswordField.delegate = self; self.RecipientField.delegate = self; self.registerClient = [[RegisterClient alloc] initWithEndpoint:BACKEND_ENDPOINT];
Teď v nástroji
AppDelegate.m
odeberte veškerý obsah metodyapplication:didRegisterForPushNotificationWithDeviceToken:
a nahraďte ji následujícím kódem (abyste měli jistotu, že kontroler zobrazení obsahuje nejnovější token zařízení načtený ze služby 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; }
Nakonec se
AppDelegate.m
ujistěte, že máte následující metodu:- (void)application:(UIApplication *)application didReceiveRemoteNotification: (NSDictionary *)userInfo { NSLog(@"%@", userInfo); [self MessageBox:@"Notification" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"]]; }
Testování aplikace
V XCode spusťte aplikaci na fyzickém zařízení s iOSem (nabízená oznámení nefungují v simulátoru).
V uživatelském rozhraní aplikace pro iOS zadejte stejnou hodnotu pro uživatelské jméno i heslo. Pak klikněte na Přihlásit se.
Mělo by se zobrazit automaticky otevírané okno s informací o úspěchu registrace. Klikněte na OK.
Do textového pole *Značka uživatelského jména příjemce zadejte značku uživatelského jména použitou při registraci z jiného zařízení.
Zadejte zprávu s oznámením a klikněte na Odeslat oznámení. Oznámení obdrží pouze zařízení, která mají registraci se značkou uživatelského jména příjemce. Odesílá se jenom těmto uživatelům.
Další kroky
V tomto kurzu jste zjistili, jak posílat nabízená oznámení konkrétním uživatelům, k jejichž registracím jsou přidružené značky. V dalším kurzu se dozvíte, jak posílat nabízená oznámení na základě polohy: