En general, se acepta que Wallet no es el servicio más popular en la CEI. Pero ya en el segundo proyecto consecutivo, el cliente establece la tarea "Realizar integración con Wallet". Por lo tanto, decidí escribir este artículo para hablar sobre el servicio en su conjunto y mostrar cómo integrar mi producto en él.
¿Qué es una billetera? Le permite mantener varios tipos de tarjetas en su teléfono (boletos, tarjetas de descuento, etc.), facilitando la vida de los usuarios del producto. Además, es posible actualizar la información sobre el mapa a través de notificaciones push, pero este es un tema para un artículo separado. Pero si tiene una tarjeta / boleto / suscripción que se puede integrar en el teléfono, ¡entonces hay una solución! Cómo hacerlo: lea a continuación.
Como regla general, su servidor es responsable de crear el mapa. La aplicación recibe la tarjeta en forma de archivo .pkpass y, a través de la aplicación, el usuario puede agregar la tarjeta a Wallet.
Estructura del mapa
¿Cuál es el mapa desde el punto de vista del desarrollador? Un mapa es un archivo con la extensión .pkpass. Contiene todos los datos necesarios para la visualización y el funcionamiento de la tarjeta. El contenido del archivo está en la tabla a continuación.
Archivo | Cita |
---|
background.png | Imagen de fondo para la tarjeta. |
footer.png | Imagen al lado del código de barras |
icon.png | Ícono para notificaciones y cartas |
logo.png | Logotipo de la tarjeta Se muestra arriba a la izquierda |
manifest.json | Registro de todos los archivos incluidos. |
firma | PKCS7 firma |
pass.json | Apariencia e información del mapa |
strip.png | Imagen ubicada detrás de la descripción principal de la tarjeta |
thumbnail.png | Imagen adicional (especificar) |
Los siguientes tipos de tarjetas están disponibles:
- Boleto de embarque: en avión o tren. Por lo general, el cupón funciona para un viaje;
- Cupón: para cupones y ofertas especiales;
- Boleto de evento: puede funcionar tanto para un evento como para una temporada completa;
- Tarjeta de descuento: tarjetas de fidelidad, tarjetas de descuento o regalo;
- Tarjeta de vista general: si nada de lo anterior se aplica a su caso: por ejemplo, una tarjeta para viajar en metro o un pase al gimnasio.
Considere esquemáticamente la apariencia de diferentes cartas. Las imágenes se nombran mejor como se indica en la tabla anterior.
Tarjeta de embarque

Cupón

Ticket de evento

Tarjeta comunitaria

Tarjeta de descuento

Estructura Pass.json
Campos obligatorios Contiene ID de tipo de pase, ID de equipo, nombre de la organización, etc.
Claves para aplicaciones relacionadas. Necesario para mostrar aplicaciones que necesitan estar "asociadas" con el mapa.
Claves de tarjetas de "fecha de caducidad".
Claves de relevancia. Por ejemplo, las coordenadas del área donde se puede usar el mapa, o el inicio del evento para el que está destinado.
La clave es el estilo. Al comienzo del artículo, se enumeraron 5 tipos de tarjetas para Wallet. Cada uno de ellos tiene su propio estilo. Tal clave debe ser estrictamente una.
Claves para el diseño visual de la tarjeta. Además de lo obvio, contienen información sobre el código de barras que se muestra en el mapa.
Claves de servicio web. Puede utilizar los servicios web para interactuar con el mapa, por ejemplo, actualizarlo automáticamente.
Llaves NFC Contiene información adicional para las transacciones de Apple Pay.
Ahora sobre todo con más detalle.
Campos obligatorios
Clave en JSON | Tipo de datos | Descripción |
---|
descripción | Cadena Localizado | Una breve descripción del mapa. Localizado |
formatVersion | Int | Versión de formato de archivo. El valor debe ser 1. |
organizationName | Cadena Localizado | El nombre de la organización que emite las tarjetas. |
passTypeIdentifier | Cadena | Pase ID de tipo y cuenta de desarrollador. |
serialNumber | Cadena | Número de serie de tarjeta única |
teamIdentifier | Cadena | ID del equipo del equipo de desarrollo |
Claves para aplicaciones relacionadas
Clave en JSON | Tipo de datos | Descripción |
---|
AssociatedStoreIdentifiers | [Int] | Opcionalmente El ID de las aplicaciones asociadas con la tarjeta. Siempre se toma el primero que es compatible con el dispositivo actual. |
appLaunchURL | Cadena | URL que se pasa a la aplicación al abrir |
Teclas de estilo
Clave en JSON | Tipo de datos | Descripción |
---|
campos primarios | [JSON] | Información básica sobre el mapa. |
campos secundarios | [JSON] | Información de antecedentes. |
Campos auxiliares | [JSON] | Campos para información adicional. Opcional |
headerFields | [JSON] | El título del mapa. Se muestra incluso cuando las tarjetas son visibles en la lista. |
Campos auxiliares | [JSON] | Información básica sobre el mapa. |
transitType | Cadena | Tipo de transporte para tarjetas de boleto. Puede tomar los siguientes valores: PK transitTypeAir, PK transitTypeBoat, PK transitTypeBu`, PK transitTypeGeneric, `PK transitTypeTrain`. |
backFields | [JSON] | Matriz de campos responsables de la parte posterior del mapa |
JSON en este caso tiene la siguiente forma:
"key" : "value1", "label" : "value2", "value" : "value3"
El valor de la clave de valor puede ser numérico o de cadena. Sin embargo, currencyCode junto con el valor de cadena no se pueden usar. En cuanto a los campos auxiliares y los campos secundarios, puede haber varios de ellos, y debe controlar la longitud de las filas que se utilizan en ellos.
Claves para el diseño visual
Clave en JSON | Tipo de datos | Descripción |
---|
códigos de barras | [JSON] | Información para el código de barras (ver abajo). |
fondoColor | color como cuerda | Color de fondo. (# Fa32e4) |
primer planoColor | color como cuerda | Color de etiqueta con valores |
groupingIdentifier | Cadena | Opcional para boletos de eventos y boletos de transporte. Las tarjetas con el mismo estilo (passTypeIdentifier y groupingIdentifier) se agruparán |
labelColor | color como cuerda | Etiquetar texto con nombres de campo |
logoText | Cadena localizable | Texto que se muestra junto al logo |
Código de barras
La parte más importante del mapa. Se le cose un número de identificación de tarjeta (por ejemplo, un número de tarjeta física o un número de boleto). Es importante que el escáner o cualquier otra herramienta pueda leer códigos en la codificación correcta.
Clave en JSON | Tipo de datos | Descripción |
---|
altText | Cadena | Texto opcional que se muestra al lado del código de barras si el código de barras no se lee. |
formatear | Cadena | Formato de código de barras. Puede tomar valores: PKBarcodeFormatQR, PKBarcodeFormatPDF417, PKBarcodeFormatAztec, PKBarcodeFormatCode128 |
mensaje | Cadena | Código o número de tarjeta encriptado en código de barras. |
mensajeEncoding | Cadena | Codificación de mensajes. Generalmente iso-8859-1 |
Ubicación
Estas claves son responsables de la ubicación dentro de la cual se puede utilizar la tarjeta.
Clave en JSON | Tipo de datos | Descripción |
---|
altiture | Cadena | Texto opcional que se muestra al lado del código de barras si el código de barras no se lee. |
latitud | Longitud | Latitud |
longitud | Doble | Latitud |
texto relevante | Cadena | Texto opcional que aparece en la pantalla de bloqueo en el momento en que el usuario ingresa al rango de la tarjeta. |
Lado trasero
Se puede colocar información adicional en la parte de información inversa: términos de uso, política de actualización automática, detalles de contacto y un enlace a la aplicación a la que pertenece la tarjeta. La figura muestra la correspondencia de los campos en pass.json y la apariencia del reverso del mapa. Si hay enlaces, números de teléfono, etc. en el campo de valor, se resaltarán automáticamente.

Crea un mapa. Parte 2
Entonces, las imágenes están listas, se forma pass.json, queda por poner todo junto. Para hacer esto, complete manifest.json (consulte la tabla 1), donde debe incluir todas las imágenes y pass.json. Resulta algo como esto:
. . . . . . "pass.json" = 303c753abc39aa732ec74643d6db28348fe8a823; "strip.png" = 736d01f84cb73d06e8a9932e43076d68f19461ff; "strip@2x.png" = 468fa7bc93e6b55342b56fda09bdce7c829d7d46; . . . . . .
A partir de este momento, no es necesario cambiar nada, ya que el SHA será incorrecto; en caso de cambios, es necesario regenerar el SHA.
A continuación, debe crear una ID de tipo de pase en la oficina del desarrollador y hacer un certificado para ello. El procedimiento debería ser más o menos familiar si creó anteriormente, por ejemplo, los perfiles de aprovisionamiento.

A continuación, vaya al Llavero y exporte desde allí el Certificado de relación de desarrollador mundial de Apple (WWDR) como .pem.

A partir de ahí, exportamos el ID de tipo de pase creado como .p12. En este punto, el ama de llaves le pedirá que ingrese la contraseña para el certificado. En este caso, una contraseña es opcional.
Tenga en cuenta que todas las acciones adicionales deben realizarse en una carpeta, donde manifest.json, pass.json y las imágenes ya deberían estar.
Ahora necesita generar una firma, que firmaremos en el archivo. Primero, exporte la ID del tipo de pase y la clave como .pem.
openssl pkcs12 -in certificate.p12 -clcerts -nokeys -out passcertificate.pem -passin pass: your_password
y
openssl pkcs12 -in certificates.p12 -nocerts -out passkey.pem -passin pass: -passout pass:new_password
Ahora estamos listos para generar una firma. Hagámoslo un comando:
openssl smime -binary -sign -certfile WWDR.pem -signer passcertificate.pem -inkey passkey.pem -in manifest.json -out signature -outform DER -passin pass:___
Entonces, todo está listo para nosotros, solo queda recopilar el archivo, hacemos esto con el comando:
zip -r nameOfPass.pkpass manifest.json pass.json signature logo.png logo@2x.png logo@3x.png icon.png icon@2x.png icon@3x.png
Le llamo la atención sobre el hecho de que todos los archivos en los que desea incluir el archivo de datos de la tarjeta (.pkpass) deben enumerarse aquí.
Como resultado, obtenemos un archivo .pkpass que se puede abrir en la computadora. Veremos una vista previa de la tarjeta, cuya apariencia puede diferir de la apariencia en el teléfono.
Todo esto se puede hacer un poco más fácil. Apple proporciona la utilidad signpass
( muestrarios de Apple Wallet ), que se encarga de todos los cálculos SHA (el archivo manifest.json
se puede dejar solo) y el trabajo de crear firmas. Para usarlo, debe crear un proyecto y colocar el archivo signpass
en una carpeta con todos los recursos necesarios.

En general, la estructura debería verse así:

A continuación, ejecute el comando:
./signpass -p wallet
Wallet es el nombre de la carpeta en la que se encuentran todos los recursos. La salida es wallet.pkpass. Su contenido se puede ver descomprimiendo wallet.pkpass.
unzip wallet.pkpass
Es posible que la creación de pkpass se envíe al backend, en cuyo caso será necesario transferir a los desarrolladores del WWDR un certificado para la ID de tipo de pase en forma de .p12 y una contraseña para ello.
Integración de aplicaciones
Para que la aplicación pueda agregar tarjetas a Wallet, debe habilitar esta función en la ID de la aplicación y también habilitar esta función en Capacidades en el proyecto.


Esto es necesario para el trabajo correcto completo con Wallet. De lo contrario, no será posible leer tarjetas de Wallet y, por ejemplo, no será posible comprender si nuestra tarjeta está agregada o no. También es importante tener en cuenta que la identificación del equipo en pass.json debe coincidir con la identificación del equipo, o deberá agregarlos manualmente a los derechos y esto puede solucionar la situación, pero no lo comprobé.

Agregar una tarjeta
Agregar mapas es muy simple:
guard let passPath = Bundle.main.path(forResource: "wallet", ofType: "pkpass") else { return } let error: ErrorPointer = ErrorPointer(nilLiteral: ()) guard let passData = NSData(contentsOfFile: passPath) else { return } let pass = PKPass(data: passData as Data, error: error) let passLibrary = PKPassLibrary() passLibrary.addPasses([pass]) { (status) in print(passLibrary.containsPass(pass)) }
Sin embargo, una vez más, el archivo .pkpass más a menudo tendrá que descargarse de su servidor.
Vale la pena señalar que PassKit produce errores bastante legibles, por lo que puede comprender fácilmente qué se hizo exactamente mal.
Para obtener información sobre las tarjetas disponibles en Wallet y relacionadas con su aplicación, debe recurrir al objeto PKPassLibrary.
let passLibrary = PKPassLibrary() let passes = passLibrary.passes()
Por lo tanto, puede comprender si el mapa se agrega o no, así como actualizar la interfaz. Además, a través de PKPassLibrary, los mapas se pueden actualizar y eliminar. Los mapas también se pueden actualizar a través de servicios web, pero en este artículo no consideraremos esa opción.
Verificación de unicidad
Como en su servicio, por regla general, la tarjeta está vinculada a una cuenta, en la aplicación lo más probable es que tenga que determinar de alguna manera si la tarjeta pertenece al usuario actual. Sugiero hacer esto a través de serialNumber
. Por ejemplo, establezca la identificación de número de serie del usuario o número de tarjeta.
Prueba
Apple proporciona ejemplos de pkpass para diferentes tipos, puede centrarse en ellos.
Muestras de billetera de manzana
Para ver cómo se ve el mapa, puede agregar pkpass al proyecto (consulte “Agregar un mapa”). El proceso de agregar / quitar ya se discutió anteriormente, solo resta recordar que la aplicación no verá las tarjetas ya agregadas si la tarjeta para Wallet se creó en una cuenta de desarrollador, y el desarrollo en sí se realizó desde otra cuenta (relevante para las empresas de outsourcing). En este caso, puede agregar tarjetas sin problemas.
Puede verificar si la información en el código de barras está codificada correctamente utilizando cualquier escáner de código QR. Y definitivamente es necesario verificar la exactitud del trabajo con este escáner.
Conclusión
El artículo examinó el proceso de creación y diseño de un mapa, así como el proceso de integración con la aplicación y los problemas que pueden surgir. Intenté no abordar problemas de integración con servicios web y actualizaciones de mapas, y espero hacerlo en el próximo artículo.
Materiales utilizados
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html
https://developer.apple.com/library/archive/documentation/UserExperience/Reference/PassKit_Bundle/Chapters/TopLevel.html#//apple_ref/doc/uid/TP40012026-CH2-SW3
https://itechroof.wordpress.com/2015/11/30/apple-wallet-part-13/
https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Updating.html
Un agradecimiento especial a mehdzor por la cuenta de desarrollador para las pruebas.