Introducción teórica al formato pkpass

En este post os voy a hablar de qué es el formato pkpass, para qué se usa, sus características más llamativas y qué ventajas tiene frente a otros formatos más tradicionales.

0. Índice de contenidos.

1. ¿Qué os voy a contar en esta entrada?

Hace un tiempo, en el proyecto en que trabajo, tuve que encargarme de una historia de usuario relacionada con el cambio de idiomas de ficheros pkpass. Después de haberme peleado con ello vi que había cosas muy curiosas y que no es fácil encontrar información al respecto. Así que he decidido contaros algunas de ellas para que no perdáis tanto tiempo como yo en buscarlo. Hay puntos en los que no he podido entrar en mucha profundidad, pero espero poder resolver las principales dudas que os surgirán al empezar a trabajar.

2. Empecemos viendo qué es pkpass

Con el lanzamiento de iOS 6 en 2012, Apple anunció una aplicación que serviría como cartera virtual para almacenar todo tipo de tarjetas, cupones y tickets: Passbook. El usuario podría tener todos estos archivos (que se llaman pases) en un mismo lugar. Además la inclusión de notificaciones en el dispositivo cuando un pase es importante en una fecha o localización también es una ventaja frente al papel tradicional. Con la llegada de iOS 9, Passbook pasaría a llamarse Wallet, pero lo que nos interesa a nosotros va por otro camino.

El formato abierto (aunque es Apple quien lo creó y lo implementa de forma nativa en sus dispositivos) que unifica los distintos tipos de pases es pkpass. Si los abrimos con una aplicación especializada lo que veremos será una especie de ticket con dos caras: frontal y posterior. Aquí tenéis como ejemplo uno de los bonos culturales que ofrece la Junta de Extremadura para poneros en contexto.

Visualización del fichero pkpass de los bonos culturales

Pero, ¿de qué nos puede servir si hasta ahora el PDF ha sido una solución más que buena? Pkpass es un tipo de archivo que se crea dinámicamente al abrirse. Por ello se adapta mucho mejor a las pantallas de los dispositivos móviles e incluso a los cambios idiomáticos (esto lo veremos más adelante). Además están firmados usando un certificado electrónico, por lo que aporta mayor seguridad sobre su origen de la que tendríamos normalmente con un PDF. Otra posibilidad muy interesante es la de cambiar un pase en el servidor y mandar una notificación push a los dispositivos móviles donde esté instalado para que se conecten y lo actualicen.

3. ¿Cómo está estructurado?

Cuando empecé creía que un archivo pkpass sería algo similar al PDF si lo abríamos, pero no es así. En realidad se trata, en esencia, de un zip. De hecho podéis descomprimir uno para ver su estructura con cualquier herramienta de compresión que tengáis instalada (seguramente tendréis que cambiarle la extensión antes, eso sí).

Dentro de la carpeta que obtenemos al descomprimir podremos encontrar los siguientes objetos:

  • background.png: imagen que sirve de fondo en la cara frontal.
  • footer.png: imagen que se muestra debajo del QR o del código de barras en la cara frontal.
  • icon.png: icono que aparece en las notificaciones y cuando se recibe el fichero por e-mail.
  • logo.png: imagen que aparece en la esquina superior izquierda.
  • manifest.json: JSON que contiene las rutas de todos los archivos que conforman el pkpass con su hash SHA-1 correspondiente. Los únicos que no aparecen listados son el propio manifest.json y el signature.
  • pass.json: JSON donde se define todo el contenido del pkpass, luego veremos qué contiene.
  • signature: manifest.json cifrado con la clave pública.
  • strip.png: imagen que se muestra detrás de los campos primarios en la cara frontal.
  • thumbnail.png: imagen adicional que podemos mostrar en el frontal.
  • Carpetas de personalización regional: en ella tendremos los cambios que contemplamos para los strings y las imágenes cuando abrimos el fichero con otra configuración regional.

Si descomprimimos el fichero pkpass del bono cultural que acabamos de ver arriba, esto es lo que obtenemos:

Estructura interna de un archivo pkpass

Ya veis que no todos los archivos que hemos puesto antes son obligatorios. Además podemos tener dos versiones de cada una de las imágenes que hemos mencionado antes. Al cargarse usando el mismo estándar que los componentes UIImage en iOS, podemos tener las imágenes de mayor resolución añadiendo @2x al final del nombre del fichero.

4. ¿Qué contiene el pass.json?

Vale, sabemos que el contenido del pkpass se define en el pass.json en forma de un diccionario de pares clave-valor. Pero, ¿qué es exactamente lo que tiene dentro y cómo se estructura? Pues se trata de un diccionario con tres niveles de claves, para permitir anidar datos, y que están clasificadas de esta forma:

  • Claves de nivel superior (top-level keys): hacen referencia a la información directa sobre el pkpass.
  • Claves de nivel inferior (lower-level keys): identifican a los elementos que sirven para definir objetos del nivel superior cuando un tipo primitivo no es suficiente.
  • Claves de campos del diccionario (field dictionary keys): definen las propiedades de los objetos del nivel inferior. Como son las últimas claves, todos sus valores serán siempre tipos primitivos.

Os dejo parte del pass.json del bono cultural para que tengáis una referencia un poco más visual.

Fragmento de un pass.json

En este ejemplo las claves formatVersion, barcode y coupon son top-level; message, format, messageEncoding, headerFields, primaryFields y backFields son lower-level, y las repetidas key, label y value son campos de diccionario.

Quiero que os paréis un segundo en el objeto coupon, que es el objeto principal del JSON. Dependiendo del tipo de pase que estamos generando tendrá un nombre u otro (boardingPass, coupon, eventTicket, storeCard o generic), pero todos permiten definir en forma de listas de objetos los campos que se mostrarán. En concreto se utilizan los headerFields, primaryFields, secondaryFields y auxiliaryFields para crear la cara frontal; mientras que para la cara posterior tenemos los backFields. Es importante tener esta estructura de campos en mente cuando queremos crear un pkpass.

Conjuntos de claves usados para cada cara

Si queréis saber más acerca las claves, lo mejor es que echéis un vistazo a la documentación oficial de Apple. Ahí encontraréis todas, para qué se utilizan, el tipo de valor que se le asigna y si son o no obligatorias.

5. Configuración regional

Y por fin hemos llegado al motivo de haber escrito esta entrada. Una de las características que he encontrado más interesantes es que pkpass permite crear un único documento que incluya la información de todos los idiomas a los que queremos traducir el pass. Frente a los formatos más tradicionales aporta mucha flexibilidad, pues normalmente tendríamos que tener una copia del documento por cada idioma al que lo traduzcamos.

Los pkpass más sencillos, como el que hemos visto arriba, asocian un valor único a cada clave que usan. Ahora bien, ¿por qué deberíamos contentarnos con poner el literal directamente en ese json? Es muy común que nuestras aplicaciones estén internacionalizadas y acepten varios idiomas. Parece lógico que intentemos aplicarlo también a los datos que compartimos, y esto es exactamente lo que se ha hecho con pkpass.

A grandes rasgos funciona exactamente igual que una aplicación típica de iOS o Mac (al fin y al cabo fue Apple quien definió el formato). En lugar de introducir todos los literales directamente vamos a tener un directorio asociado a cada idioma para el que tenemos traducciones (con el nombre codigo_idioma.lproj), dentro del cual habrá un fichero pass.strings. En estos ficheros tenemos una especie de diccionario en el que asociamos una clave que para nosotros tiene un significado con su traducción en el lenguaje que corresponda. Cuando escribimos el pass.json no pondremos los literales directamente, sino la clave que hemos definido en nuestros pass.strings. Al abrir el pkpass se cargarán automáticamente los valores del idioma que deba y se le mostrará traducido al usuario de forma completamente transparente para él.

Aquí os pongo un pequeño ejemplo de cómo aplicar esto para traducir las etiquetas de un pase en español e inglés.

Ejemplo de configuración regional

Pero esto no es todo. Dentro de las carpetas de localización también es posible incluir imágenes que sustituirán a las que hay definidas por defecto. Simplemente debemos darles el mismo nombre que las originales.

Aquí os dejo un enlace a la documentación oficial de cómo Apple internacionaliza sus aplicaciones, pues es exactamente el mismo principio. Pero a modo de explicación rápida os diré que al abrir el archivo mira la configuración de región del sistema que lo abre (ordenador, móvil, iPod…) y busca entre los idiomas para los que tengamos traducciones el que ofrezca una mejor correspondencia.

6. Notificaciones en la pantalla de bloqueo

La última de las características que voy a comentar con mayor profundidad es la de poder lanzar una notificación para que aparezca en la pantalla de bloqueo del dispositivo cuando se han cumplido una serie de condiciones. En una entrada de cine, por ejemplo, podríamos configurarla para que se active al acercarnos a unos metros del cine de forma que la tengamos ya preparada en la pantalla cuando la necesitemos para entrar.

Para lograr esto utilizamos las claves de relevancia (relevance keys), que pueden ser de tres tipos y servir para definir bien localizaciones o fechas:

  • beacons: podemos especificar un conjunto de lugares mediante los beacons que haya en ellos. Cuando nos hayamos acercado lo suficiente como para captar su señal, el pkpass será válido y se mostrará en la pantalla de bloqueo.
  • locations: igual que antes, nos sirve para definir un conjunto de lugares, pero esta vez lo haremos en base a sus coordenadas (latitud, longitud y altitud). Podemos añadir también la clave maxDistance para especificar un radio alrededor de estos puntos en los que saltará la notificación.
  • relevantDate: en este caso nos permite indicar una fecha y hora en formato W3C (obligatorio al menos hasta los segundos) a la que deberá aparecernos la notificación.

Os dejo aquí también un pequeño ejemplo, por si verlo en código os ayuda a entenderlo mejor.

Ejemplo de cómo usar las claves de relevancia

7. Lo que no debemos olvidar al trabajar con archivos pkpass

Por último quería tener un apartado en el que agrupar los pequeños detalles que no encajaban del todo en los anteriores y que no eran lo suficientemente extensos (o no he entrado demasiado en profundidad en ellos). Pero como han sido un pequeño dolor de cabeza no quería terminar sin que os sonaran.

7.1. Cabeceras para devolver y pedir

Si queremos que un servicio devuelva un fichero en formato pkpass debemos especificar en la cabecera de la respuesta HTTP que el Media Type es application/vnd.apple.pkpass. En el siguiente trozo de código podéis ver cómo se hace en Java.

Eso sí, si queremos que todo funcione bien no podemos olvidar indicar el mismo tipo de archivo en la cabecera Accept de nuestra petición HTTP. Si no, lo único que vamos a obtener será un archivo que no seremos capaces de abrir, o como mucho un error que nos avise de esto.

7.2. Qué ocurre si no tenemos un certificado o no es válido

Recordad que originalmente los ficheros pkpass están firmados con un certificado creado por Apple. Si por cualquier motivo el certificado no existe, ha caducado o simplemente no es válido tendremos problemas para abrirlo. En MacOS, hasta Sierra, se abrirá sin problemas pero el código QR aparecerá inactivo y sobre él habrá un texto indicando que algo ha ido mal. Si lo abrimos con Sierra o cualquier versión de iOS (tanto en iPhone como en iPod) simplemente no se abrirá. Si queréis algo más de información al respecto lo mejor es que abráis la consola del sistema y busquéis el error.

Ahora bien, resulta que las aplicaciones para Android solamente miran el contenido en sí de los pases y no comprueban si la firma que hay en el signature es correcta. Esto se traduce en que aunque el certificado sea inválido por cualquier motivo, nuestro fichero se abrirá normalmente sin que se le muestre nada al usuario.

7.3. Un formato para confundirnos a todos: espass

Mientras preparaba esta entrada tuve curiosidad por ver más ejemplos de pkpass y me puse a buscar los pases que tenía guardados. Lo que encontré fue otro formato muy parecido al pkpass, llamado espass. Se trata de un estándar aún en construcción para la generación de pases inteligentes. Lo que se pretende con ellos es mejorar la venta de tickets (cupones, tarjetas de embarque y pases similares), especialmente en materias de seguridad de acceso y contra la reventa de tickets.

Tienen la misma base estructural que los pkpass, por lo que si lo descomprimimos encontraremos unos cuantos archivos de recursos para las imágenes y un main.json en el que se especifica todo el contenido. Si bien el json es mucho más simple en este caso y no cuenta con una estructura de claves tan bien definida como la de los pkpass.

No obstante, aunque en estructura y apariencia sean similares, en un principio no parecen estar pensados para lo mismo (habrá que ver cómo evoluciona espass). Precisamente a esto se debe la falta de complejidad en la definición de los datos y la ausencia de la mayoría de las características importantes que hemos visto aquí. Lo único que quería era que supieseis que hay un estándar de nombre y resultado visual similar y que puede abrirse con las mismas aplicaciones que el pkpass, no plantearlo como una alternativa real.

Desde su web muy parecido al pkpass, llamado podéis descargar un par de ejemplos, pero es posible que lo único que podáis hacer sea descomprimirlo para verlo por dentro. Para visualizarlo parece que la única opción es usar la aplicación PassAndroid (no es necesario que digamos para qué plataforma), que es la que tienen puesta en la misma web. Llevado por la curiosidad, he intentado abrirlos con mi Mac y con el iPhone de un compañero y ninguno de los dos ha reconocido el formato.

8. Conclusiones

Hemos visto que pkpass es un formato muy flexible y que aporta muchas ventajas sobre los tipos más tradicionales como el PDF. Para compartir cualquiera de los tipos de pases que soporta es una opción idónea, y si lo usamos bien nos ayudará mucho, tanto como desarrolladores como de cara al negocio para el que se vayan a implementar.

Pero no os llevéis la impresión equivocada, pkpass no va a ser el sustituto del PDF. Se trata más bien de una alternativa para ofrecer nuestra información al usuario. No olvidemos que está muy limitado en la estructura de los documentos que podemos generar, mientras que PDF permite cualquier cosa que se nos ocurra. Además, aunque en dispositivos de Apple se haga de manera nativa, los usuarios con un teléfono Android deben tener un mínimo conocimiento de la existencia de este formato como para querer descargarse una aplicación que permita abrirlo. Como desarrolladores, creo que la mejor idea sería implementar las dos aproximaciones y dejar que sea el propio usuario el que elija qué formato prefiere.

9. Referencias