Tutorial: enviar notificações por push para usuários específicos usando os Hubs de Notificação do Azure
Este tutorial mostra como usar os Hubs de Notificação do Azure para enviar notificações por push a um usuário específico do aplicativo em um dispositivo específico. Um back-end da API Web ASP.NET é usado para autenticar clientes e gerar notificações, conforme mostrado no tópico de diretrizes Registrando-se por meio do back-end do aplicativo.
Neste tutorial, você deve executar as seguintes etapas:
- Criar o projeto WebAPI
- Autenticar clientes para o back-end da WebAPI
- Registrar para receber notificações usando o back-end da WebAPI
- Enviar notificações do back-end da WebAPI
- Publicar o novo back-end da API Web
- Modificar seu aplicativo iOS
- Testar o aplicativo
Pré-requisitos
Este tutorial pressupõe que você criou e configurou seu hub de notificação como descrito em Enviar notificações por push para aplicativos iOS usando os Hubs de Notificações do Azure. Este tutorial também é um pré-requisito para o tutorial Push Seguro (iOS) . Se desejar usar os Aplicativos Móveis como seu serviço de back-end, veja Mobile Apps Get Started with Push.
Criar o projeto WebAPI
As seções a seguir abordam a criação de um novo back-end WebAPI ASP.NET. Esse processo tem três objetivos principais:
- Autenticar clientes: adicione um manipulador de mensagens para autenticar solicitações de cliente e associar o usuário à solicitação.
- Registrar para receber notificações usando o back-end WebAPI: adicione um controlador para lidar com novos registros para que um dispositivos clientes recebam notificações. O nome de usuário autenticado é automaticamente adicionado ao registro como uma marca.
- Enviar notificações aos clientes: adicione um controlador para permitir aos usuários disparar um envio por push seguro para dispositivos e clientes associados à marca.
Crie o novo back-end da API Web do ASP.NET 6.0 Core executando estas ações:
Para verificar, inicie o Visual Studio. No menu Ferramentas, selecione Extensões e Atualizações. Pesquise por Gerenciador de Pacotes NuGet na sua versão do Visual Studio e verifique se a versão mais recente está instalada. Se a versão não for a versão mais recente, desinstale-a e reinstale o Gerenciador de Pacotes NuGet.
Observação
Verifique se você instalou o SDK do Azure do Visual Studio para implantação de site.
Inicie o Visual Studio ou o Visual Studio Express.
Selecione Gerenciador de Servidores e entre na sua conta do Azure. Para criar os recursos de site na sua conta, você precisará estar conectado.
No menu Arquivo do Visual Studio, selecione Novo>Projeto.
Insira API Web na caixa de pesquisa.
Selecione o modelo do projeto da API Web do ASP.NET Core e, em seguida, Avançar.
Na caixa de diálogo Configurar o novo projeto, nomeie o projeto AppBackend e selecione Avançar.
Na caixa de diálogo Informações adicionais:
- Confirme se o Framework é o .NET 6.0 (suporte de longo prazo).
- Confirme se a caixa de seleção para Usar controladores (desmarcar para usar APIs mínimas) está marcada.
- Desmarque Habilitar suporte a OpenAPI.
- Selecione Criar.
Remover os arquivos de modelo WeatherForecast
- Remova os arquivos de exemplo WeatherForecast.cs e Controllers/WeatherForecastController.cs do novo projeto AppBackend.
- Abra Properties\launchSettings.json.
- Altere as propriedades launchUrl de weatherforcast para appbackend.
Na janela Configurar o Aplicativo Web do Microsoft Azure, selecione uma assinatura e, na lista Plano do Serviço de Aplicativo, execute uma destas ações:
- Selecione um plano do Serviço de Aplicativo do Azure que você já criou.
- Selecione Criar um novo plano do serviço de aplicativo para criar um.
Não é necessário um banco de dados para este tutorial. Depois que você tiver selecionado o seu plano de serviço de aplicativo, selecione OK para criar o projeto.
Se você não vir essa página para configurar o plano do serviço de aplicativo, continue com o tutorial. Você pode configurá-la ao publicar o aplicativo mais tarde.
Autenticar clientes para o back-end da WebAPI
Nesta seção, você cria uma nova classe de manipulador de mensagens denominada AuthenticationTestHandler para o novo back-end. Essa classe é derivada de DelegatingHandler e adicionada como um manipulador de mensagens para poder processar todas as solicitações que chegam ao back-end.
No Gerenciador de Soluções, clique com botão direito do mouse no projeto AppBackend, selecione Adicionare selecione Classe.
Nomeie a nova classe AuthenticationTestHandler.cs e selecione Adicionar para gerar a classe. Essa classe usa Autenticação Básica para manter a simplicidade na autenticação dos usuários. Seu aplicativo pode utilizar qualquer esquema de autenticação.
Em AuthenticationTestHandler.cs, adicione as seguintes instruções
using
:using System.Net.Http; using System.Threading; using System.Security.Principal; using System.Net; using System.Text; using System.Threading.Tasks;
Em AuthenticationTestHandler.cs, substitua a definição da classe
AuthenticationTestHandler
pelo código a seguir:Esse manipulador autoriza a solicitação quando as três seguintes condições a seguir forem verdadeiras:
- A solicitação inclui um cabeçalho de Autorização.
- A solicitação usa a autenticação básica .
- A cadeia de caracteres de nome de usuário e a cadeia de caracteres de senha são iguais.
Caso contrário, a solicitação é rejeitada. Essa não é uma abordagem de autenticação e autorização verdadeira. É apenas um exemplo simples para este tutorial.
Se a mensagem de solicitação for autenticada e autorizada pelo
AuthenticationTestHandler
, o usuário de autenticação básica será anexado à solicitação atual no HttpContext. As informações do usuário no HttpContext serão usadas por outro controlador (RegisterController) posteriormente para adicionar uma marca à solicitação de registro de notificação.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; } }
Observação
Nota de segurança: a classe
AuthenticationTestHandler
não oferece autenticação verdadeira. Ela é usada somente para imitar a autenticação básica e não é segura. Você deve implementar um mecanismo de autenticação seguro em seus aplicativos e serviços de produção.Para registrar o manipulador de mensagens, adicione o seguinte código ao final do método
Register
no arquivo Program.cs:config.MessageHandlers.Add(new AuthenticationTestHandler());
Salve suas alterações.
Registrar para receber notificações usando o back-end da WebAPI
Nesta seção, você adiciona um novo controlador ao back-end WebAPI para manipular solicitações e registrar um usuário e um dispositivo para notificações usando a biblioteca de cliente dos hubs de notificação. O controlador adiciona uma marca de usuário ao usuário que foi autenticado e anexado a HttpContext pelo AuthenticationTestHandler
. A marca tem o formato de cadeia de caracteres, "username:<actual username>"
.
No Gerenciador de Soluções, clique com o botão direito do mouse no projeto AppBackend e selecione Gerenciar Pacotes NuGet.
No painel esquerdo, selecione Online e, na caixa Pesquisa, digite Microsoft.Azure.NotificationHubs.
Na lista de resultados, selecione Hubs de Notificação do Microsoft Azure e selecione Instalar. Conclua a instalação e, por fim, feche a janela Gerenciador de Pacotes NuGet.
Essa ação adiciona uma referência ao SDK dos Hubs de Notificação do Azure usando o pacote NuGet Microsoft.Azure.Notification Hubs.
Crie um novo arquivo de classe que representa a conexão com o hub de notificação usado para enviar notificações. No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Modelos, selecione Adicionar e Classe. Nomeie a nova classe como Notifications.cs e selecione Adicionar para gerar a classe.
Em Notifications.cs, adicione a seguinte instrução
using
à parte superior do arquivo:using Microsoft.Azure.NotificationHubs;
Substitua a definição da classe
Notifications
pelo seguinte e substitua os dois espaços reservados pela cadeia de conexão (com acesso completo) para o hub de notificação e o nome do hub (disponível no portal do 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>"); } }
Importante
Insira o nome e a DefaultFullSharedAccessSignature do seu hub antes de prosseguir.
Em seguida, crie um novo controlador chamado RegisterController. No Gerenciador de Soluções, clique com o botão direito do mouse na pasta Controladores, selecione Adicionar e Controlador.
Selecione Controlador da API – Vazio e Adicionar.
Na caixa Nome do controlador, digite RegisterController para nomear a nova classe e selecione Adicionar.
Em RegisterController.cs, adicione as seguintes instruções
using
:using Microsoft.Azure.NotificationHubs; using Microsoft.Azure.NotificationHubs.Messaging; using AppBackend.Models; using System.Threading.Tasks; using System.Web;
Adicione o código a seguir à definição de classe
RegisterController
. Nesse código, você adiciona uma marca de usuário para o usuário anexado a HttpContext. O usuário foi autenticado e anexado a HttpContext pelo filtro de mensagens que você adicionou,AuthenticationTestHandler
. Você também pode adicionar verificações opcionais para conferir se o usuário tem direitos para registro das tags requeridas.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()); } }
Salve suas alterações.
Enviar notificações do back-end da WebAPI
Nesta seção, você adiciona um novo controlador que expõe uma maneira de os dispositivos clientes enviarem uma notificação. A notificação se baseia na marca de nome de usuário que usa a Biblioteca .NET dos Hubs de Notificação do Azure no back-end WebAPI ASP.NET.
Crie outro novo controlador chamado NotificationsController da mesma maneira que você criou RegisterController na seção anterior.
Em NotificationsController.cs, adicione as seguintes instruções
using
:using AppBackend.Models; using System.Threading.Tasks; using System.Web;
Adicione o seguinte método à classe NotificationsController:
Esse código envia um tipo de notificação com base no parâmetro
pns
do PNS (Platform Notification Service). O valor deto_tag
é usado para definir a marca username na mensagem. Essa marca deve corresponder a uma marca de nome de usuário de um registro de hub de notificação ativo. A mensagem de notificação é recuperada do corpo da solicitação POST e formatada para o PNS de destino.Dependendo do PNS que seus dispositivos com suporte usam para receber notificações, as notificações têm suporte por vários formatos diferentes. Por exemplo, em dispositivos do Windows, você pode usar uma notificação do sistema com WNS que não tenha suporte direto de outro PNS. Nesse caso, o back-end precisa formatar a notificação em uma notificação com suporte para o PNS de dispositivos aos quais você planeja dar suporte. Em seguida, use a API de envio apropriada na 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); }
Para executar o aplicativo e garantir a precisão de seu trabalho até aqui, selecione a tecla F5. O aplicativo abre um navegador da Web e será exibido na home page do ASP.NET.
Publicar o novo back-end da API Web
Em seguida, implante o aplicativo em um site do Azure para poder ser acessado por todos os dispositivos.
Clique com o botão direito do mouse no projeto AppBackend e selecione Publicar.
Escolha Serviço de Aplicativo do Microsoft Azure como destino de publicação e selecione **Publicar. A janela Criar Serviço de Aplicativo é aberta. Aqui, você pode criar todos os recursos do Azure necessários para executar o aplicativo Web ASP.NET no Azure.
Na janela Criar Serviço de Aplicativo, selecione sua conta do Azure. Selecione Alterar Tipo>Aplicativo Web. Mantenha o Nome do Aplicativo Web padrão e selecione a Assinatura, o Grupo de Recursos e o Plano do Serviço de Aplicativo.
Selecione Criar.
Anote a propriedade URL do Site na seção Resumo. Essa URL será seu ponto de extremidade de back-end mais adiante no tutorial.
Selecione Publicar.
Depois de concluir o assistente, ele publica o aplicativo Web ASP.NET no Azure e abre o aplicativo no navegador padrão. Seu aplicativo pode ser exibido nos Serviços de Aplicativo do Azure.
A URL usa o nome do aplicativo Web especificado anteriormente, com o formato http://<app_name>.azurewebsites.net.
Modificar seu aplicativo iOS
Abra o aplicativo de exibição de Página Única que você criou no tutorial Enviar notificações por push para aplicativos iOS usando Hubs de Notificação do Azure.
Observação
Nesta seção, presumimos que você configurou seu projeto com um nome de organização vazio. Caso contrário, preceda o nome da sua organização a todos os nomes de classe.
No arquivo
Main.storyboard
, adicione os componentes mostrados na captura de tela da biblioteca de objetos.Nome de usuário: um UITextField com texto de espaço reservado, Inserir nome de usuário, imediatamente abaixo de enviar rótulo de resultados e restrito às margens esquerda e direita e abaixo do rótulo de resultados de envio.
Senha: um UITextField com texto de espaço reservado, Digite a senha, imediatamente abaixo do campo de texto Nome de usuário e restrito às margens esquerda e direita e abaixo do campo de texto Nome de usuário. Verifique a opção Entrada de texto seguro no Inspetor de atributo, em Retornar chave.
Fazer logon: um UIButton chamado imediatamente abaixo do campo de texto de senha e desmarque a opção Habilitado no Inspetor de atributos, em Conteúdo de controle
WNS: o rótulo e o comutador para habilitar o envio da notificação do Serviço de Notificação do Windows, se ele tiver sido configurado no hub. Confira o tutorial Introdução ao Windows.
GCM: o rótulo e a opção para habilitar o envio da notificação para o Google Cloud Messaging, se ele tiver sido configurado no hub. Consulte o tutorial Introdução ao Android .
APNS: o rótulo e a opção para habilitar o envio da notificação ao Apple Platform Notification Service.
Nome do Usuário do Destinatário: um UITextField com texto de espaço reservado marca de nome de usuário do destinatário, imediatamente abaixo do rótulo GCM e restrita às margens esquerda e direita e abaixo do rótulo do GCM.
Alguns componentes foram adicionados no tutorial Enviar notificações por push para aplicativos iOS usando Hubs de Notificação do Azure.
Use Ctrl e arraste os componentes na exibição para
ViewController.h
e adicione essas novas saídas:@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;
No
ViewController.h
, adicione o seguinte#define
após as instruções de importação. Substitua o espaço reservado<Your backend endpoint>
pela URL de destino que você usou para implantar o back-end do aplicativo na seção anterior. Por exemplohttp://your_backend.azurewebsites.net
:#define BACKEND_ENDPOINT @"<Your backend endpoint>"
Em seu projeto, crie uma nova classe Cocoa Touch chamada
RegisterClient
para fazer a interface com o back-end ASP.NET que você criou. Criar a classe herdeira deNSObject
. Em seguida, adicione o seguinte código aoRegisterClient.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
No
RegisterClient.m
, atualize a seção@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
Substitua a seção
@implementation
no RegisterClient.m pelo código a seguir:@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
Este código implementa a lógica explicada no artigo de orientação Registrando-se a partir do back-end do seu aplicativo, utilizando NSURLSession para realizar chamadas de REST para o back-end do seu aplicativo e NSUserDefaults para armazenar localmente o registrationId retornado pelo hub de notificação.
Essa classe requer que sua propriedade
authorizationHeader
seja configurada para funcionar adequadamente. Essa propriedade é definida pela classeViewController
após o logon.Em
ViewController.h
, adicione uma instrução#import
aRegisterClient.h
. Em seguida, adicione uma declaração para o token do dispositivo e faça referência a uma instânciaRegisterClient
na seção@interface
:#import "RegisterClient.h" @property (strong, nonatomic) NSData* deviceToken; @property (strong, nonatomic) RegisterClient* registerClient;
No ViewController.m, adicione uma declaração de método privado à seção
@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
Observação
O snippet a seguir não é um esquema de autenticação seguro, você deve substituir a implementação de
createAndSetAuthenticationHeaderWithUsername:AndPassword:
pelo seu mecanismo de autenticação específico que gera um token de autenticação a ser consumido pela classe de cliente do registro, por exemplo, OAuth, Active Directory.Em seguida, na seção
@implementation
doViewController.m
, adicione o seguinte código que adiciona a implementação para definir o cabeçalho de autenticação e o token do dispositivo.-(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; }
Observe como a configuração do token do dispositivo ativa o botão Fazer logon. Isso ocorre porque, como parte da ação de logon, o controlador de exibição se registra para notificações por push no back-end do aplicativo. Não queremos que ação de Fazer logon seja acessível até que o token do dispositivo seja configurado corretamente. É possível desacoplar o login do registro push desde que a primeira opção ocorra antes da última citada.
Em ViewController.m, use os trechos de código a seguir para implementar o método de ação em seu botão Fazer logon e um método para enviar a mensagem de notificação usando o back-end do 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]; }
Atualizar a ação para o botão Enviar notificação para usar o back-end do ASP.NET e enviar a qualquer PNS habilitado por um comutador.
- (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]; }
Na função
ViewDidLoad
, adicione o código a seguir para instanciar a instânciaRegisterClient
e definir o delegado para os seus campos de texto.self.UsernameField.delegate = self; self.PasswordField.delegate = self; self.RecipientField.delegate = self; self.registerClient = [[RegisterClient alloc] initWithEndpoint:BACKEND_ENDPOINT];
Agora, em
AppDelegate.m
, remova todo o conteúdo do métodoapplication:didRegisterForPushNotificationWithDeviceToken:
e substitua-o pelo seguinte (para se certificar de que o controlador de exibição contenha o token de dispositivo mais recente, recuperado de 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; }
Por fim, em
AppDelegate.m
, verifique se você tem o seguinte método:- (void)application:(UIApplication *)application didReceiveRemoteNotification: (NSDictionary *)userInfo { NSLog(@"%@", userInfo); [self MessageBox:@"Notification" message:[[userInfo objectForKey:@"aps"] valueForKey:@"alert"]]; }
Testar o aplicativo
No XCode, execute o aplicativo em um dispositivo iOS físico (as notificações por push não funcionam no simulador).
Na interface do usuário do aplicativo iOS, insira o mesmo valor para o nome de usuário e senha. Em seguida, clique em Fazer logon.
Você deverá ver um pop-up informando sobre o sucesso da inscrição. Clique em OK.
No campo de texto *Marca de nome de usuário do destinatário , insira a marca de nome de usuário usada com o registro de outro dispositivo.
Digite uma mensagem de notificação e clique em Enviar notificação. Somente os dispositivos que têm um registro com a marca de nome de usuário do destinatário recebem a mensagem de notificação. Isso é enviado somente aos usuários.
Próximas etapas
Neste tutorial, você aprendeu como enviar notificações por push para usuários específicos que têm tags associadas seus registros. Para saber como enviar notificações por push, vá para o tutorial a seguir: