Las tarjetas digitales, generalmente, se utilizan en teléfonos o relojes inteligentes. Cada marca suele tener su propia aplicación para gestionar los pases. Apple tiene Apple Wallet, Samsung utiliza Samsung Wallet, etc… A pesar de estas distinciones de las marcas, hay dos métodos que destacan sobre los demás:

  • Apple Wallet: la billetera de Apple, lee los archivos .pkpass del dispositivo y permite añadirlos como pases. Solo sirve para dispositivos iOS.
  • Google Wallet: la billetera de Google es una aplicación que se puede instalar en todos los dispositivos Android. Usando Google Cloud, es posible hacer llamadas a la API de Google Wallet y añadir tarjetas a un usuario de Google.

 

Generación de tarjetas en Apple

 

Para crear pases digitales válidos en Apple Wallet será necesario obtener varios certificados:

  • WWDR de Apple
  • Certificado de la cuenta de desarrollador
  • Claves privadas del certificado de la cuenta de desarrollador

Estos servirán para firmar en el pase y permitirá a Apple Wallet verificar que la procedencia del archivo .pkpass es de una fuente fiable. Todo el proceso de firmado se puede realizar con openssl y desde una terminal.

Para firmar el pase se tendrán que crear unos ficheros  que almacenarán la información de este, los ficheros deben estar dentro de un directorio denominado paquete del pase, los archivos son:

  • pass.json: contiene la estructura del pase.
  • manifest.json: contiene un JSON cuyas claves serán la ruta relativa de un archivo dentro del pase y el valor será el SHA1 de ese fichero.
  • icon.png: icono del pase.
  • signature: firma generada con openssl.

Aparte de estos ficheros obligatorios, se pueden añadir ficheros opcionales según las características que tenga un pase. Por ejemplo, hay pases que permiten añadir otras imágenes visibles dentro de este, como por ejemplo un strip o un thumbnail. Estos archivos son opcionales, pero si se quieren añadir habría que introducir strip.png o thumbnail.png dentro del paquete del pase. Para más información sobre la estructura de los distintos tipos de pases y los ficheros obligatorios y opcionales, se recomienda revisar la documentación de Apple. También muestra los distintos campos que tienen los pases y el tipo de dato a introducir en esos campos, si uno de los campos tienen un tipo de dato incorrecto el pase no funcionará.

Una vez construido el pass.json, hay que construir el manifest.json. Este archivo es un JSON que contiene como claves las rutas relativas de los archivos dentro del paquete del pase y cuyo valor será el SHA1 del archivo. Ni el signature ni el manifest.json tienen que tener un hash representativo dentro de este archivo ya que, el primero hasta ahora no se ha generado (ya se verá cómo generarlo) y el segundo no tendría sentido añadirlo. Por ejemplo, tenemos el siguiente pase con los siguientes archivos:

pasePrueba/
|->pass.json
|->icon.png
|->thumbnail.png

El manifest.json tendría la siguiente estructura:

{
“pass.json”: <SHA1 de pass.json>,
“icon.png”: <SHA1 de icon.png>,
“thumbnail.png”: <SHA1 de thumbnail.png>
}

El manifest.json se almacenaría en el paquete del pase de la siguiente manera:

pasePrueba/
|->pass.json
|->icon.png
|->thumbnail.png
|->manifest.json

Una vez se tengan los ficheros creados con la información necesaria se podría proceder a la firma. Usando openssl se tendría que firmar el manifest.json, el comando devolverá un fichero que representará la firma y este se almacenará junto a pass.json, manifest.json y el resto de archivos en el paquete del pase. El comando para firmar un pase sería similar al siguiente:

openssl smime -binary -sign -certfile <WWDR> -signer <PK certificado> -inkey <certificado> -in <manifest.json> -out <signature> -outform DER -passin pass:<contraseña certificado>

Esto firmará el manifest.json y creará un archivo signature, una vez firmado se comprime el paquete del pase en un archivo .pkpass. Para comprimir a .pkpass  es necesario comprimir en .zip y cambiarlo de formato manualmente a .pkpass. Para más información sobre la firma se recomienda consultar la documentación. Si todo ha funcionado correctamente debería poder abrirse, si no, podremos debuggear (solo si estamos en MAC) abriendo la aplicación Consola y recogiendo los logs del sistema al abrir la tarjeta, ahí se mostrará el porqué ésta falla.

 

Maqueta de la aplicación Apple Wallet con un pase a añadir.

 

Generación de tarjetas en Google

 

A diferencia del sistema de Apple, que consiste en generar unos archivos representan las tarjetas, en Google existe una API a la cual se puede acceder y que asocia una tarjeta a una cuenta. Todo el proceso de creación, firma y almacenamiento de tarjetas lo realizan estos endpoints de la API y es necesario desarrollar la funcionalidad desde cero.

Para comenzar a emitir tarjetas en Google, es necesario tener una cuenta en Google Cloud Console. Desde ahí se habilitará la API de Google Wallet y se podrá crear una cuenta de servicio, que se usará para autenticarse. Cada cuenta que habilita la API tiene un issuerId, el cual se utilizará para asociar las tarjetas que generemos a nuestra cuenta de emisor. Para más información sobre cómo empezar a utilizar el servicio de Google, pulsa aquí.

El sistema de Google se basa en clases e instancias (también llamadas objetos), tanto clases como objetos tienen un ID para identificarlos, en el caso de las clases sigue la siguiente estructura “IdEmisor.IdClase” y para los objetos la siguiente “IdEmisor.IdObjeto”. En este sistema, las instancias heredarán atributos de las clases pero nunca al revés.

 

 

Herencia de clases y objetos en un pase.

 

 

Una clase almacena información sobre la estructura de la tarjeta o información compartida por todos los usuarios que vayan a tener ese pase, por ejemplo, en el caso de pases de embarque, la clase almacenaría la estructura de la información a mostrar: información sobre el vuelo tal como la hora y el aeropuerto de salida y llegada, entre otros campos, los cuales son campos compartidos por todos los pasajeros.

Por otro lado, los objetos incluirán información solo visible para el usuario que tenga ese pase específicamente en su cuenta, por ejemplo, el nombre y apellidos, un número de referencia único, entre otros, en resumidas cuentas, la información del usuario. Como se ha mencionado, estos objetos heredarán la información de la clase de manera que, la tarjeta final contendrá la información de la clase a la que pertenece, en este caso habrá información del vuelo y del pasajero.

En lo que respecta al desarrollo, Google ofrece una librería de Java y un SDK para poder llamar al servicio de forma sencilla. Usando las funciones que se ofrecen en ambas alternativas, se realizará las distintas llamadas REST al servicio, para más información sobre las distintas llamadas y sus componentes, puedes hacer click aquí. El link anterior también contiene información sobre la estructura de cada tipo de tarjeta.

Para crear una tarjeta, será necesario construir primero la clase, a partir de esa clase, es posible construir los objetos. Las clases desde la librería de Java se construyen usando GenericClass, LoyaltyClass, GiftClass, entre otras, según el tipo de clase que se desee construir, tras esto se llamaría a la función REST insert desde el servicio.

Para comprobar las clases creadas y su información, se puede acceder a la consola del emisor. En esta pantallas se mostrará una lista de las clases existentes y la información para cada una de ellas, también se pueden actualizar los campos si es necesario.

Para generar un objeto, hay que asociarlo a una clase y asegurarse de que el tipo del objeto es igual al de la clase. Desde la librería de Java los objetos se construyen utilizando GenericObject, LoyaltyObject, GiftObject, entre otros, según el tipo. Usando el endpoint insert de la API es posible crear el objeto. Para enviar la tarjeta al usuario final se tiene que enviar mandar un link con un token devuelto por la API al firmar el pase.

 

JWT generado.

 

Token generado a partir de ese JWT.

 

 

A la hora de crear un objeto en Google se elabora una instancia en forma de JWT, la cual se puede enviar con una llamada a la API. Esta llamada firmará el token usando un secreto, en caso de la librería de Java se utilizarán las credenciales de la cuenta de servicio. Una vez firmado, la llamada devolverá un token, este token podrá usarse para enviar el pase al usuario final. Para ello, habrá que enviar el siguiente link al usuario:

https://pay.google.com/gp/v/save/<token-devuelto>

Si la clase y el objeto se han generado correctamente, el link debería funcionar y, al acceder a él, debería mostrar la aplicación de wallet y el pase para añadir. Para obtener más información sobre cómo funciona la firma de pases en Google Wallet se puede revisar el siguiente enlace.

Actualizar pases en Apple

 

Para actualizar pases en Apple hay que construir un Web Service capaz de gestionar las siguientes llamadas:

  1. Registro de un dispositivo: en una base de datos, almacenar la relación entre un dispositivo y un pase. El pushToken recibido en el cuerpo es el id del dispositivo.
  2. Obtener listados de pases por actualizar: para un dispositivo, enviar los números de serie de los pases sin actualizar.
  3. Devolver un pase: para un número de serie, devolver el .pkpass correspondiente.
  4. Eliminar un pase: cuando el usuario elimine un pase en su billetera, eliminar la relación entre este y el dispositivo.

 

Diagrama de funcionamiento general del Web Service.

 

El archivo .pkpass almacenará la ruta base del Web Service para saber adónde enviar las llamadas. Una vez el pase tiene la ruta al Web service, el dispositivo que porta el pase se encarga de realizar las llamadas y recibir y gestionar las respuestas automáticamente. Dentro de estas llamadas, el Web Service tendrá otras funciones o llamadas para actualizar la información almacenada en un pase.

Una vez nos aseguramos de que el pase ha sido añadido al dispositivo del usuario, tendremos que registrarlo en nuestro dispositivo. Esta función de registro consistirá en almacenar la información del pase y del dispositivo para posteriormente comprobar si el pase ha recibido una actualización.

 

Diagrama del registro de un pase y un dispositivo.

 

De igual forma, se deberá de poder eliminar de nuestro Web Service la relación entre el pase y el dispositivo.

 

Diagrama de la eliminación de un pase y un dispositivo.

 

Aunque se actualice la información donde la tengamos almacenada en nuestro servicio (generalmente una base de datos), los pases en los dispositivos de los usuarios no se van a actualizar. Para esto, Apple ofrece utilizar un APNs, que enviará notificaciones “invisibles” al dispositivo.

 

Diagrama del envío de una notificación al cliente.

 

Estas notificaciones no serán visibles para el propietario del dispositivo, pero servirán para avisar sobre la actualización de uno o varios pases. Por otro lado, cuando el dispositivo recibe una notificación invisible, llamará al endpoint encargado de obtener el listado de los pases por actualizar (2), el endpoint devolverá una lista de números de serie a actualizar y por cada elemento de la lista, si existe un pase almacenado con ese número de serie en el dispositivo, se enviará una petición para obtener el pase (3). Para más información sobre este proceso, se puede visitar este enlace.

 

Diagrama de la obtención de los pases actualizados y la actualización de estos.

 

Para el envío de la notificación invisible, se puede utilizar openssl y los certificados utilizados para la firma del pase.

curl -v –header «apns-topic: <passTypeId>» –header «apns-push-type: alert» –cert <certificado> –cert-type PEM –key <PK del certificado> –key-type PEM –data ‘{«aps»:{«alert»:»test»}}’ –http2 https://api.push.apple.com/3/device/<idDispositivo> –pass <contraseña del certificado>

El teléfono recibirá la notificación y solicitará los serialNumbers de los pases a actualizar. Apple recomienda crear una base de datos para almacenar la información de los pases y su fecha de última actualización, pero se pueden usar otras vías alternativas. Una vez devuelta la lista de serialNumbers, el dispositivo preguntará por la actualización de los pases cuyos números coincidan con alguno de la lista. Si los endpoints están correctamente programados, este proceso se hará de forma automática (salvo el envío de la notificación “invisible” de actualización).

Actualizar pases en Google

 

En el caso de Google, se puede actualizar un pase usando los endpoints de la API. Automáticamente se le mostrará el pase con la nueva información al usuario final, no será necesario hacer nada más. Además, Google permite actualizar la clase, haciendo que automáticamente se actualice cierta información para todas las tarjetas pertenecientes a la misma.

Enviar notificaciones en pases en Apple

 

Actualizar el pase automáticamente es importante para mejorar la experiencia de usuario, pero también para poder añadir envío de notificaciones a los pases de Apple. Cuando un pase se actualiza automáticamente, se puede añadir que muestre una o varias notificaciones. Es posible hacerlo añadiendo el campo changeMessage en los atributos passFields de pass.json, aquí se pueden ver cuáles son esos campos. Si incluimos un changeMessage, al enviarle el nuevo pase al dispositivo, este mostrará una notificación cuyo texto será el valor de este campo.

Enviar notificaciones en pases en Google

 

Con respecto a las notificaciones, Google funciona de una manera similar a Apple. Las notificaciones son un atributo (Message) dentro de la tarjeta y se pueden añadir más o menos según convenga. Hay dos formas de añadir estos mensajes:

  1. Actualizar el pase añadiendo los mensajes de forma manual al objeto o la clase.
  2. 2. Usar el endpoint addMessage.

También se permite añadir mensajes a una clase, de tal forma que, todos los pases pertenecientes a esa clase recibirán el mismo mensaje.

Google limita el número de mensajes que se pueden enviar por tarjeta por día. En este caso, cada tarjeta solo puede recibir tres mensajes en un mismo día.