Tutorial: Notificações Push no iOS

Olá pessoal, No post de hoje vamos entender um pouco melhor como funcionam as notificações push no iOS e também vamos desenvolver uma app para poder testar o que aprendermos neste post. Apesar de particularmente não ser experiente no desenvolvimento de apps nativas com Objective C, notificações Push é um dos recursos que eu acho mais simples de se trabalhar nativamente do que usar PhoneGap ou Sencha Touch.

ios7-push-04

No iOS não podemos fazer muito no background. As apps podem executar um conjunto limitado de atividades para conservar a bateria (e ninguém iria usar uma app que fica usando toda a bateria né?). Mas e se alguma coisa muito legal acontecer e você quiser notificar o usuário, mesmo que o usuário não esteja usando a sua app? Neste caso, podemos usar notificações push. As notificações push podem fazer 3 coisas: mostrar um texto curto, executar um alerta em forma de som e setar um número (badge) no ícone da aplicação. Você pode escolher que a sua notificação push faça apenas uma dessas coisas listadas ou até mesmo as três.

Requisitos

Para este tutorial você vai precisar de:

  1. um iPhone ou iPad - notificações Push não funcionam no simulador, por isso precisamos de um aparelho Apple para poder testar na prática
  2. ser desenvolvedor cadastrado no programa iOS da Apple - para conseguir testar apps num iPhone ou iPad, é necessário criar um App ID e um Provisioning Profile, que só pode ser feito através do developer center da Apple. Já publiquei aqui no blog como se faz para se tornar um desenvolvedor iOS da Apple.
  3. um servidor que esteja conectado a internet - você pode usar o seu próprio computador. Vou usar o Xampp como webserver.
  4. Mac OS e Xcode - como vamos criar uma aplicação nativa, é necessário ter o XCode instalado no seu computador, que precisa rodar o Mac OS.

Nível do tutorial: Avançado

Overview: Como as Notificações Push Funcionam

Enviar notificações Push não é uma tarefa trivial, pois dependemos de vários módulos como podemos ver no diagrama a seguir: notifcacoespushios-loiane 1 - primeiro temos que habilitar o uso de notificações Push na app. O usuário vai confirmar de deseja receber notificações Push ou não.

2 - A app recebe um token. Esse token é como se fosse o endereço para onde as notificações push serão enviadas.

3 - A app envia o token para o seu servidor. Nesse caso precisamos de ter um código server (php, java, ou qualquer outra linguagem) que recebe esse token e deixa ele gravado em algum lugar para usar esse token (endereço no futuro).

4 - Quando algo de interessante acontecer e você quer que o usuário seja notificado através de uma notificação Push, o seu código server envia a notificação para o servidor APNS (Apple Push Notification Service).

5 - O servidor APNS irá enviar a notificação para o aparelho do usuário.

Alguns poréns: não podemos confiar 100% em notificações push. Pode acontecer delas não serem entregues. Tem que tomar cuidado com a quantidade de notificações push que enviamos, pois primeiro precisamos enviar para o servidor APNS da Apple e este será responsável por enviar a notificação. E o APNS trabalha com filas. Vamos ver nesse post todo o código necessário para enviar uma notificação Push de teste, tanto o código Objective C quanto o código server (em PHP). Vamos antes de codificarmos alguma coisa, tem alguns passos que precisamos executar.

Gerando o Certificate Signing Request (CSR)

Bem, se você já testou alguma app em um aparelho (iPhone, iPod ou Ipad) você já deve saber desses passos a seguir. Mas para enviar notificações Push, precisamos de 2 passos extras. Esse é um deles, que é gerar um CSR.

Abra a aplicação Keychain Access (Applications/Utilities) e no meu escolha a seguinte opção:

ios7-push-05

Se você não tem a opção Request a Certificate From a Certifica Authority, instale primeiro o  WWDR Intermediate Certificate.

A seguinte janela irá aparecer: no email, é bom colocar o mesmo email que vc usa no Apple iOS Dev Center. O no Common Name vamos colocar o nome da app que vamos criar (PushChat). Não esqueça de checar a opção Save to disk e clique em Continue:

ios7-push-06

Abra as Keys e localize a chave que acabamos de criar. Clique com o botão direito do mouse e escolha Export "PushChat":

ios7-push-07

Você precisa entrar com um passphrase/senha para criptografar o certificado. Escolhi pushchat mesmo para facilitar. Não esqueça disso pois vamos precisar logo mais.

Criando um App ID e Certificado SSL

Agora vamos criar um App ID e configurar para usar notificações Push. Entre no iOS Dev Center e escolha Certificates, Identifiers & Profiles:

ios7-push-08

Escolha Identifiers:

ios7-push-09

Vá em App IDS e clique no botão + para criar uma nova App ID:

ios7-push-10

Dê um nome para a App:

ios7-push-11

Escolha um nome para o pacote:

ios7-push-12

E não podemos esquecer de marcar a opção Push Notifications:

ios7-push-13

Termine de criar o App ID, e quando terminar, vai voltar para a lista de App IDs. Clique em cima da App ID que acabamos de criar e clique em Settings:

ios7-push-14

Vamos configurar o certificado SSL. Para isso, localize Push Notifications e clique em Create Certificate:

ios7-push-15

Siga os passos até a seguinte tela. Nessa tela vamos fazer o upload do arquivo que criamos no tópico anterior. Depois é só clicar em Generate:

ios7-push-16

Faça o download do arquivo e salve em algum lugar do seu computador - é um arquivo chamado aps_development.cer

ios7-push-17

Gerando o Arquivo PEM

Até agora temos os seguintes arquivos:

  • O CSR
  • O private key como p12 file (PushChatKey.p12)
  • O certificado SSL, aps_development.cer

Todos os arquivos salvei no desktop. Agora vamos usar o terminal para criar mais alguns arquivos. Como salvei todos no meu desktop, vou trocar o diretório:

[code lang="bash" firstline="1" toolbar="true" collapse="false" wraplines="false"]cd ~/Desktop/[/code]

Depois vamos converter o arquivo  .cer em .pem:

[code lang="bash" firstline="1" toolbar="true" collapse="false" wraplines="false"]openssl x509 -in aps_development.cer -inform der -out PushChatCert.pem[/code]

E também vamos converter o arquivo .p12 em .pem:

[code lang="bash" firstline="1" toolbar="true" collapse="false" wraplines="false"]<br />openssl pkcs12 -nocerts -out PushChatKey.pem -in PushChatKey.p12<br />Enter Import Password:<br />MAC verified OK<br />Enter PEM pass phrase:<br />Verifying - Enter PEM pass phrase:<br />[/code]

Primeiro precisamos entrar com o passphrase para o arquivo .p12 para que o openssl possa let. Depois você precisa entrar com um passphrase que será usado para encriptar o arquivo PEM. Usei sempre pushchat para facilitar de lembrar! Mas em uma app de verdade que será executada em produção crie um passphrase mais complicado.

E finalmente vamos combinar o certificado e a chave em um único arquivo .pem:

[code lang="bash" firstline="1" toolbar="true" collapse="false" wraplines="false"]cat PushChatCert.pem PushChatKey.pem &gt; ck.pem[/code]

Agora vamos testar para ver se o certificado funciona. Execute o seguinte comando:

[code lang="bash" firstline="1" toolbar="true" collapse="false" wraplines="false"]<br />telnet gateway.sandbox.push.apple.com 2195<br />Trying 17.172.232.226...<br />Connected to gateway.sandbox.push-apple.com.akadns.net.<br />Escape character is '^]'.<br />[/code]

Esse comando tenta fazer uma conexão não encriptada para o servidor APNS. Como podemos ver, a mensagem consegue chegar até o APNS. Pressione Ctrl+C para fechar a conexão. Se você obtiver uma mensagem de erro, tenha certeza de que a porta 2195 não esteja bloqueada pelo firewall. O resultado no terminal de todos os comandos acima vai ser esse: ios7-push-24 Por último, vamos tentar conectar com o servidor APNS novamente, mas deste vez usando nosso certificado SSL e a chave privada para uma conexão segura:

[code lang="bash" firstline="1" toolbar="true" collapse="false" wraplines="false"]<br />openssl s_client -connect gateway.sandbox.push.apple.com:2195 -cert PushChatCert.pem -key PushChatKey.pem<br />Enter pass phrase for PushChatKey.pem:<br />[/code]

No output irão aparecer várias coisas, como no screenshot abaixo: ios7-push-25 Tudo pronto para o próximo passo!

Criando o Provisioning Profile

Agora chegou a hora de criar o Provisioning Profile. E temos que ter cuidado ao criar esse arquivo, pois tudo vai depender dele. Muitas pessoas não conseguem testar e obtém mensagem de erro quando for gerar o device token. Nesse caso basta apagar e gerar o provisioning profile novamente.

Vamos lá!

De volta ao iOS Dev Center, selecione Provisioning Profile e clique para criar um novo:

ios7-push-18

Selecione iOS App Development e clique em Continue:

ios7-push-19

Selecione o App ID que criamos:

ios7-push-20

Selecione o certificado de desenvolvedor:

ios7-push-21

Selecione os devices que você quer testar a app:

ios7-push-22

E dê um nome ao profile e clique em generate:

ios7-push-23

Não precisa fazer o download pois o XCode automaticamente irá fazer o download pra gente.

Criando uma App para Testes

Agora vamos abrir o XCode e criar uma app Single View Application:

ios7-push-26

Dê um nome para a App, e o nome do pacote - muita atenção pois precisa ser os mesmos de  quando criamos o App ID, senão não irá funcionar:

ios7-push-27

Abra o arquivo AppDelegate.m e mude o método application:didFinishLaunchingWithOptions: para que fique assim:

[code lang="cpp" firstline="1" toolbar="true" collapse="false" wraplines="false"]- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {<br /> // Let the device know we want to receive push notifications<br /> [[UIApplication sharedApplication] registerForRemoteNotificationTypes:<br /> (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];<br /><br /> return YES;<br />}[/code]

Isso vai fazer com que a app mostre a popup de confirmação para o usuário confirmar se quer ou não receber notificações Push. Mas precisamos também saber qual é o token, pois sem isso não conseguimos enviar a mensagem. Para isso adicione o seguinte código dentro da classe AppDelegate.m:

[code lang="cpp" firstline="1" toolbar="true" collapse="false" wraplines="false"]<br />- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken<br />{<br /> NSLog(@"My token is: %@", deviceToken);<br />}<br /><br />- (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error<br />{<br /> NSLog(@"Failed to get token, error: %@", error);<br />}[/code]

Agora nossa app está pronta!

Instale e execute a app no seu device (mas não esqueça de executar a app com o USB conectado para podermos ver os logs e pegar o token). E como esperado, a app vai perguntar se queremos receber notificações push. Clique em OK:

ios7-push-01

E no log do Xcode vamos ver uma mensagem assim:

My token is: <eada5820da66f33b10ea6b7dc599965519fe3c17443b750595ba66a9396624b1>

Guarde esse token pois vamos precisar dele.

Enviando a Notificação Push

Agora vamos para o código PHP!

Esse é o código que vamos usar. Criei um arquivo chamado simplepush.php e coloquei o seguinte código nele:

[code lang="php" firstline="1" toolbar="true" collapse="false" wraplines="false" highlight="4,7,10, 15"]<br />&lt;?php<br /><br />// Put your device token here (without spaces):<br />$deviceToken = 'eada5820da66f33b10ea6b7dc599965519fe3c17443b750595ba66a9396624b1';<br /><br />// Put your private key's passphrase here:<br />$passphrase = 'pushchat';<br /><br />// Put your alert message here:<br />$message = 'Minha primeira notificação push!';<br /><br />////////////////////////////////////////////////////////////////////////////////<br /><br />$ctx = stream_context_create();<br />stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');<br />stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);<br /><br />// Open a connection to the APNS server<br />$fp = stream_socket_client(<br /> 'ssl://gateway.sandbox.push.apple.com:2195', $err,<br /> $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);<br /><br />if (!$fp)<br /> exit("Failed to connect: $err $errstr" . PHP_EOL);<br /><br />echo 'Connected to APNS' . PHP_EOL;<br /><br />// Create the payload body<br />$body['aps'] = array(<br /> 'alert' =&gt; $message,<br /> 'sound' =&gt; 'default'<br /> );<br /><br />// Encode the payload as JSON<br />$payload = json_encode($body);<br /><br />// Build the binary notification<br />$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;<br /><br />// Send it to the server<br />$result = fwrite($fp, $msg, strlen($msg));<br /><br />if (!$result)<br /> echo 'Message not delivered' . PHP_EOL;<br />else<br /> echo 'Message successfully delivered' . PHP_EOL;<br /><br />// Close the connection to the server<br />fclose($fp);<br />[/code]

Temos que prestar atenção em 3 linhas do código acima:

Linha 4: é o token do device, é o endereço para onde a notificação push será enviada.

Linha 7: não podemos esquecer do passphrase que usamos para criptografar o certificado.

Linha 11: A mensagem que vamos usar na notificação push.

Linha 15: o arquivo .pem que geramos. Nesse caso, coloquei esse arquivo no mesmo diretório do arquivo php.

E no final, vamos fazer o teste!

Basta executarmos o arquivo php que criamos:
ios7-push-28

Resultado

E alguns segundos depois (tenha certeza de que o dispositivo tenha conexão com internet - wifi ou 3G) e nossa notificação vai aparecer na tela do celular:

ios7-push-02

Esse tutorial vale tanto para iOS 6 quanto para iOS 7! :)

Download do Código Fonte

Código Objective-c (Xcode): https://github.com/loiane/ios-examples/tree/master/PushChat

Código php: https://github.com/loiane/ios-examples/tree/master/PushServer

Referência

Até a próxima! :)