Conectar web y móvil vía chat

October 13, 2014

Cuando visitamos un comercio físico, el dependiente reacciona a nuestra entrada ofreciendo su ayuda y obteniendo asímismo valiosa información que puede servir para mejorar el negocio e incluso convertirnos de visitantes en clientes. ChatKaizen1 es una aplicación destinada a los comercios web, que he desarrollado con esta idea en mente.

No es una idea original mía, ya existen soluciones similares, como la de Olark. Para que pueda usarse, se instala en la página web un widget2 que permite conectar por chat en tiempo real a los visitantes de una web con el personal detrás de esa web. El chat se inicia normalmente en la página web y se puede atender desde dispositivos móviles, p.ej. smart phones, o desde otra interfaz web de trastienda.

El Web Widget

ChatKaizen, de momento, solo tiene trastienda para terminales Android. El widget se instala en una web ya existente añadiendo el siguiente trozo de código:

<script type="text/javascript" 
        src="http://appkaizen.herokuapp.com/appkaizen.js?user_id=XXXX" async>
</script>

p.ej. antes de la etiqueta de cierre </body>. En el atributo src, XXXX se sustituye por el identificador de usuario previamente registrado y proporcionado al responsable de la web en que se vaya a instalar el widget. Otras opciones se pueden pasar al widget de forma similar a como se pasa el identificador de usuario con user_id.

El cargador del widget, implementado en el fichero appkaizen.js, está escrito en JavaScript utilizando las librerías jQuery y Socket.IO, con la inspiración del artículo How to build a web widget (using jQuery). Lo más importante del cargador es aislar el código para no interferir con la página “anfitriona”, encerrando el código en una función anónima y cargar las librerías ya nombradas si no están disponibles.

El proyecto de este componente se encuentra en https://github.com/clapas/kaizen-chat-relay.

El retransmisor de charla

Este componente hace de interfaz entre el widget y el bot XMPP3. Se ejecuta bajo un motor de Node.js alojado en la PaaS (Platform-as-a-Service) de Heroku. Y de forma similar a cómo las GitHub Pages se gestionan con un repositorio Git (ver GitHub y Jekyll para mi web), sucede lo mismo con Heroku, e.d. tengo el proyecto versionado en un repositorio Git, y subiendo los cambios con un git push heroku master, Heroku despliega la aplicación y queda visible al público.

Node.js es perfecto para esta aplicación, porque permite mantener multitud de conexiones no bloqueantes, tantas como páginas web con el widget instalado haya abiertas. El número de conexiones no sería una preocupación si todos los navegadores soportaran Web Sockets, y en unos años así será. Pero mientras muchos navegadores dependan del long polling para implementar eventos iniciados tanto por el cliente como por el servidor, Node.js es una alternativa ideal.

Con la librería Socket.IO consigo abstraerme de los detalles de la comunicación entre el navegador y el servidor, ya que ofrece una API uniforme que envuelve el transporte específico que use, p.ej. AJAX long-polling, JSONP long-polling, Web Sockets, etc. Socket.IO proporciona APIs tanto para el lado del cliente –navegador, como del servidor –Node.js, muy semejantes entre sí, con lo que el círculo queda completo.

El proyecto de este componente se encuentra en https://github.com/clapas/kaizen-chat-relay.

El Bot XMPP

Cada visitante de la web puede usar el widget para comunicarse con un operador que atenderá la charla desde su terminal Android. Esto significa que los visitantes deben poder distinguirse unos de otros desde el terminal del operador. Además, para soportar la charla, lo ideal es utilizar un protocolo destinado a tal fin, como es XMPP (eXtensible Messaging and Presence Protocol). Para facilitar la comunicación, la solución pasaría por asociar internamente cada visitante con una cuenta de usuario de XMPP4 única.

Las cuentas de usuario de XMPP podrían crearse ad hoc instalando y configurando mi propio servidor XMPP, pero hay una solución más sencilla: usar el servicio de XMPP para Google App Engine. Así, al tiempo que resuelvo el problema de las cuentas de usuario de XMPP, dispongo de una PaaS donde desplegar la aplicación que gestiona las entidades de ChatKaizen, p.ej. clientes, operadores, etc.

App Engine me resuelve el problema de las cuentas de usuario ad hoc porque asocia automáticamente cualquier cuenta que siga el patrón <usuario>@appkaizen.appspotchat.com/<recurso> con mi aplicación, donde <usuario> y <recurso> son cualquier cosa que yo elija –siempre que los caracteres sean válidos, claro. Es decir, que puedo componer un mensaje estableciendo como remitente un JID4 cualquiera y, cuando el destinatario responda, Google se lo entrega a mi aplicación.

Por cierto, esta vez he usado Java, uno de los lenguajes soportados por el App Engine de Google. Y para no tener que lidiar con problemas de comunicación Servidor-a-Servidor, voy a requerir que las cuentas de XMPP para el cliente Android sean también de Google; más sobre esto después.

Quizás se pregunte: ¿por qué no gestionar directamente los mensajes de la web en el mismo servidor, p.ej. en el de App Engine? Yo me lo pregunté…5 Pues por lo que se comentó arriba de que Node.js es ideal para evitar conexiones bloqueantes, sencillamente. Esto me supone añadir un enlace más en la comunicación entre el navegador y el terminal Android, con el retardo que ello supone, pero creo que está justificado.

Resumiendo, el retransmisor de charla envía los mensajes de los visitantes de la web al bot XMPP que se comunica con el terminal Android por XMPP, y la respuesta desde el terminal Android es entregada por el servicio XMPP de App Engine a mi aplicación que, a su vez, se la pasa al retransmisor de charla para que la haga llegar al visitante de la web.

El proyecto de este componente se encuentra en https://github.com/clapas/kaizen-xmpp-bot.

La Android App

Este componente es el que permite a los operadores o dependientes atender a los visitantes de la web independientemente de dónde estén, con tal de que tengan una conexión a Internet. P.ej. pueden estar en un tren o un restaurante cuando reciben en su terminal Android una consulta en tiempo real de un visitante de la web interesado en sus productos/servicios.

Para implementar el cliente Android he utilizado los archivos JAR compilados por el sistema de generación aSmack de librerías Smack para Android. Recientemente se ha publicado la versión 4.1 alfa de Smack que incluye soporte nativo para Android; por tanto, el sistema aSmack pronto dejará de ser necesario.

Como ya se mencionó más arriba, he requerido que el usuario del terminal Android tenga registrada alguna cuenta con Google para acceder al servicio XMPP de Google6. El cliente Android, en su versión inicial, utilizará la primera cuenta de Google que encuentre para conectar con los servidores de Google. La autenticación se lleva a cabo bajo el protocolo OAUTH2 con el mecanismo SASL plano, donde la clave de acceso es un token de acceso obtenido del servidor de cuentas de Google.

El cliente Android de ChatKaizen solo procesa paquetes provinientes del bot XMPP de ChatKaizen. Se espera que cada nueva conversación se inicie con una solicitud de subscripción para la cuenta XMPP asociada que se crea por el bot; la solicitud es aceptada automáticamente por la aplicación. Sucesivos mensajes se van asociando con cada una de las cuentas como conversaciones separadas.

A nivel de usuario, la app de Android muestra dos pantallas (o actividades en terminología Android): en la primera se muestra una lista de elementos, uno por cada nueva conversación; en la segunda se muestra los mensajes de la conversación y un campo de edición para enviar nuevos mensajes, y se accede haciendo click sobre cualquiera de los elementos del listado de la primera pantalla.

El proyecto de este componente se encuentra en https://github.com/clapas/kaizen-android-client.


  1. inspirado en el termino japonés Kaizen que se traduce como “cambio a mejor” o “mejora”.

  2. elemento gráfico que se empotra en la interfaz de usuario, p.ej. una ventanita que se muestra superpuesta en una página web.

  3. un bot es un robot web, encargado de ejecutar tareas automatizadas.

  4. las cuentas de XMPP se denominan JID (Jabber ID), y son como una dirección de correo que al final pueden contener la barra ‘/’ seguida de un identificador de recurso, p.ej. usuario@servidor_xmpp.com/recurso. 2

  5. Una alternativa para esto sería usar la API Channel de Google, que es similar a mi combinación NodeJS + Socket.IO.

  6. Desde su anuncio en el Google I/O de mayo de 2013, Google ha retirado la interoperabilidad entre servidores XMPP (federación XMPP) y ha adoptado Hangouts como servicio de mensajería instantánea y videoconferencia, pero se espera que el servicio siga activo entre usuarios de Google.

Archivos