lunes, 22 de abril de 2013

Android: Jugando con las notificaciones push de Google Cloud Messaging




Todo el mundo conoce las notificaciones Push como el típico mensajito que nos sale en la pantalla del teléfono cuando recibimos un mensaje de Whatsapp o un correo electrónico. Este tipo de notificaciones, desde el punto de vista de Android, se montan con el servicio de Google Cloud Messaging. En el día de hoy solo vamos a ver como montar el ejemplo que la librería nos trae por defecto, y en futuras ediciones realizaremos nuestra propia aplicación desde cero.

Descarga de las librerías

Para poder trabajar con Google Cloud Messaging (en adelante CGM) tendremos que descargarnos las librerías haciendo uso de la herramienta SDK Manager. Para abrirlo, en nuestro Eclipse accederemos al menú Windows > Android SDK Manager.


Una vez abierto, nos moveremos hacia abajo y en Extras localizaremos Google Cloud Messaging for Android Library. Lo seleccionaremos y lo instalaremos.



Una vez instalado, con el explorador iremos al directorio de nuestro SDK > extras  > google > gcm y ahí tendremos localizadas tanto las librerías como los ejemplos. Si accedemos a los ejemplos podremos ver 3 directorios, de los cuales a nosotros nos interesan dos:
  • gcm-demo-client: aplicación Android para nuestro dispositivo que será el cliente.
  • gcm-demo-server: aplicación web para nuestro servidor Java (Apache Tomcat) que hará de servidor.


Montando el ejemplo de servidor

Para instalar el servidor, copiaremos el directorio gcm-demo-server dentro del workspace de NetBeans 7.x (por ejemplo, en mi caso: C:\Users\jose.c.arcenegui\workspace). Una vez copiado el directorio, desde NetBeans crearemos un  nuevo Proyecto Java Web > Web Application with Existing Sources.


Seleccionaremos nuestro directorio copiado, y el resto de opciones por defecto.


Seguramente nos indique que hay un archivo build.xml y que debemos indicar un nuevo nombre: seleccionamos el que nos indique por defecto.


Y por supuesto, cuando nos pregunte por nuestro servidor web donde desplegaremos, le diremos que Apache Tomcat.


Y listo, ya tenemos nuestro proyecto web importado que podremos desplegar.


Una vez publicado en Apache Tomcat podremos ver como nuestra nueva aplicación web.






Preparando el cliente

Con nuestro servidor ya montado, toca jugar con nuestro teléfono/tablet. En Eclipse, navegamos al menú File > Import…


Y seleccionamos Existing Android Code Into Workspace


Indicamos la ruta de nuestro ejemplo gcm-demo-client (directorio del sdk\extras\google\gcm\samples\gcm-demo-client) y marcamos el proyecto DemoActivity y  la opción copy projects into workspace.


Y al finalizar tendremos el proyecto listo para desplegar en nuestro dispositivo, aunque antes deberemos realizar una serie de cambios.

Creación del proyecto GCM

Antes de seguir, deberemos crearnos un proyecto de GCM desde la web https://code.google.com/apis/console

Al crearlo, nos devolverá un identificador del proyecto


Tras esto, deberemos ir a Services y marcar la opción Google Cloud Messaging for Android.



Y en API Access deberemos crear un API Server Key



Cambios en el proyecto Android

Deberemos realizar una serie de cambios en nuestro proyecto Android antes de desplegar en la clase CommonUtilities.


Indicaremos la URL del servidor en SERVER_URL y el Project Number en SENDER_ID


MUY IMPORTANTE: Recuerda indicar la IP y no pongas localhost!!!

Si ahora ejecutamos la aplicación en nuestro dispositivo veremos que es capaz de registrarse en GCM pero no en nuestro servidor.



Pasa que esto funciona deberemos aplicar una serie de cambios en nuestra aplicación web.

Cambios en el servidor

Editaremos el archivo WEB-INF/api.key y copiaremos nuestra API Key que generamos desde la web.


Una vez realizado este cambio, podremos volver a desplegar y probar, registrando nuestro dispositivo.


Y en la web nos saldrá que tenemos un dispositivo registrado y que podemos probar a enviar mensajes.



En el siguiente post haremos nuestra propia aplicación con notificaciones Push.

11 comentarios:

  1. una duda cuando modifico el archivo api.key me sigue diciendo que no tengo ningun servidor gracias
    espero tu respuesta

    ResponderEliminar
  2. Javier, es algo raro que no te pille el cambio en api.key. ¿Has comprobado si tienes saltos de carro o espacios en el archivo?

    De todas formas, hay una forma de formar a usar esa clave por código: en la clase ApiKeyInitializer puedes cambiar la linea String key = getKey(); por String key = "tu clave GCM";

    De todas formas, te recomiendo leer el post "Android: Creando nuestra aplicación push I: montando el servidor" donde hago este paso de forma diferente.

    ResponderEliminar
  3. Este comentario ha sido eliminado por el autor.

    ResponderEliminar
  4. Buenas tardes, Excelente ejemplo y muy bien explicado. Aunque no se porque no me funciona, me aparece que esta registrado y en el servidor me dice que hay 2 dispositivos conectados(lo cual es verdad), pero al enviar los mensajes desde el servidor estos nunca llegan a los celulares, ¿alguna idea?.
    Gracias.

    ResponderEliminar
    Respuestas
    1. Es posible que sea por la red en la que se encuentra el dispositivo. En mi caso me pasó algo parecido: registraba el dispositivo desde la WIFI (protegida) y sin embargo, la mensajería no le llegaba. No obstante, al desactivar la WIFI si llegaban las notificaciones push.

      Espero que sea eso. Ya me comentas!

      Eliminar
  5. Buenas, muchas gracias por el post. Tengo una duda que no he conseguido resolver, por mucho que he mirado en Internet. Si el usuario tiene dos dispositivos, y queremos que se le envíen notificaciones a los dos, tenemos que registrar ambos dispositivos y almacenar el id devuelto por GCM en nuestra base de datos.
    En este caso, deberíamos crear una tabla, donde el identificador de usuario y el del GCM sean clave primaria conjunta, pues debemos permitir tener varios identificadores para cada usuario, uno por dispositivo. Habría que añadir un campo que identifique al dispositivo, cuál sería el más adecuado? MAC sólo valdría si siempre se conecta por WIFI, y el identificador del teléfono es fácilmente modificable si el teléfono está rooteado. Se puede acceder al mismo id que tiene Google del teléfono, el que le permite saber a qué terminal debe enviar un mensaje, en función del identificador de registro que le asignó previamente?

    Muchas gracias!!

    ResponderEliminar
    Respuestas
    1. No llego a entender bien tu pregunta, así que espero responderte.

      Cuando registras un dispositivo en GCM con la función GCMRegistrar.getRegistrationId(this) o con GCMRegistrar.register(this, SENDER_ID) devuelve el identificador del dispositivo en GCM (servidor de google).

      Como bien dices puedes guardar en tu servidor de la aplicación la relación usuario-id de dispositivo y al realizar un push, hacerlo a todos los dispositivos de ese usuario.

      Creo que al final te he dicho lo mismo que tu me has escrito :S

      Eliminar
    2. Gracias por tu respuesta. Intento aclararlo:

      Supongamos que un usuario ha accedido a la aplicación mediante dos dispositivos, una tablet y un móvil. Tenemos por tanto en la tabla dos registros con el par (id_usuario,id_GCM), pongamos (5,'765234785') y (5,'78658693') por ejemplo.

      Yo a priori no sé que uno es para la tablet y otro para el móvil de ese usuario. Cuando el usuario acceda a la aplicación desde el móvil, si GCM me proporciona un nuevo id_GCM, tendré que actualizar el existente, y si no he identificado el dispositivo, no sabré cuál de los dos registros actualizar. Si actualizo el de la tablet, por ejemplo, me dejará de enviar notificaciones al móvil.

      Una opción sería no actualizar sino insertar un nuevo registro cada vez. Lo que ocurre es que GCM dará error al enviar un mensaje a un dispositivo cuyo identificador ha caducado, sin contar con que estaremos haciendo peticiones innecesarias.

      Por eso comentaba lo de la necesidad de identificar el dispositivo y saber cuál actualizar en cada caso.

      Uf, no sé si estoy liándolo todo.

      Eliminar
    3. Acabo de encontrar la respuesta. Lo que hay que hacer es un envío multicast, para empezar. No sé si hacer un envío multicast para cada usuario (contando con que pueda tener varios dispositivos), o para todos los dispositivos de los usuarios elegidos. Según como sea de complicada la segunda opción, que es, lógicamente, la más rápida, elegiré un método u otro.
      La clave está en que cuando envías un mensaje a un id y éste ha caducado, GCM te envía de vuelta su id canónica, algo así como un id nuevo, asociado al antiguo, que deberemos utilizar las siguientes veces en lugar del último id proporcionado.
      Cuando hacemos un envío multicast, le pasamos al método una lista de id, y la respuesta contiene también una lista. La respuesta al id en la posición j de la lista de entrada se encontrará en la posición j de la lista respuesta.

      Por tanto, deberemos analizar la lista de respuesta, comprobar si nos están enviando alguna id canónica, y en ese caso, actualizar, tomando como id a actualizar la que figuraba en la misma posición en la lista que le pasamos al método de envío.

      Espero haberme explicado y que le sirva de ayuda a alguien.

      Eliminar
  6. Buenas, tengo una app y me gustaría una vez enviada la notificación push al otro usuario como desactivar el servicio, es decir, yo tengo una activity y hago uso de la clase GCMIntentService para mandar la notificación, a continuación quiero desactivar esta clase porque más adelante vuelvo a hacer uso del sistema push pero en otro activity y utilizando otra clase GCMIntentService2. Ya que el problema es que al recibir el push en el otro dispositivo lo recibe por el GCMIntentService y no por el nuevo GCMIntentService2.

    Muchas Gracias por tu tiempo y muy buen tuto!!

    ResponderEliminar
  7. buenas tardes sabras donde se ubica el String que llega al dispositivo "you got a message" gracias.

    ResponderEliminar