Portada de UrsaKit para la guía de crear y firmar un pase de Apple Wallet

Un pase de Apple Wallet (el archivo .pkpass) es un ZIP firmado, no un formato de documento. Wallet no muestra un pase inválido con una advertencia: se niega a añadirlo, y por eso la mayoría de la gente conoce este formato mirando un pase que simplemente no abre. Esta guía construye uno a partir de sus cuatro partes obligatorias y luego cubre los fallos que provocan un rechazo silencioso.

Apple también ofrece Pass Designer para diseñar pases de forma visual, y puedes usarlo para prototipar el diseño. Cuando el pase lo debe generar un servidor, en cambio, construyes el archivo tú mismo.

01Qué contiene realmente un archivo .pkpass

Renombra cualquier pase que funcione a .zip, descomprímelo y encontrarás estas piezas:

Archivo¿Obligatorio?Función
pass.jsonSíDefinición del pase: identificadores, estilo, colores, código, campos
manifest.jsonSíHash SHA-1 de cada uno de los demás archivos
signatureSíFirma PKCS#7 separada de manifest.json
icon.png, icon@2x.pngSíEl icono pequeño que muestra Wallet
logo.png, strip.png, miniaturasSegún estiloArte opcional, con los tamaños de Apple

El manifest es la capa de integridad, y los pasos de compilación de Apple lo mantienen deliberadamente simple: un objeto JSON plano que asigna la ruta de cada archivo de origen a su digest SHA-1 en hexadecimal. Nunca se incluye a sí mismo ni a la firma, y tampoco debe listar metadatos como .DS_Store.

{
  "icon.png": "6c4f1b2a4e2b7d3c9a5f8e1d0b6a3c2e4f5a6b7c",
  "logo.png": "b1d2c3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0",
  "pass.json": "9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c"
}

El manifest debe coincidir exactamente con el ZIP

Si manifest.json lista logo@2x.png y ese archivo no existe, o si hay un archivo en el ZIP que no aparece en el manifest, la validación de la firma falla y Wallet rechaza el pase. Regenera el manifest después de cada cambio de imagen.

02Construye pass.json para los cinco estilos

Todos los pases comparten unas claves superiores y luego declaran exactamente un estilo. Las claves comunes son formatVersion (siempre 1), passTypeIdentifier, serialNumber, teamIdentifier, organizationName y description. Si tu servidor publica actualizaciones, también necesitas webServiceURL y authenticationToken.

El diccionario de estilo es uno de generic, storeCard, coupon, eventTicket o boardingPass. Cada estilo expone regiones distintas: un pase de embarque tiene primaryFields, secondaryFields, auxiliaryFields y backFields en posiciones fijas, mientras que un pase genérico usa las mismas regiones con otra intención.

Los campos tienen tope. En general un pase admite hasta tres campos de cabecera, un campo primario, cuatro secundarios y cuatro auxiliares; un pase de embarque permite dos primarios y cinco auxiliares, y los cupones, tarjetas de fidelización y pases genéricos con código cuadrado comparten cuatro campos secundarios y auxiliares entre ellos. (Guía de PassKit)

{
  "formatVersion": 1,
  "passTypeIdentifier": "pass.com.example.loyalty",
  "serialNumber": "member-8842",
  "teamIdentifier": "ABCDE12345",
  "organizationName": "Example Coffee",
  "description": "Example Coffee loyalty card",
  "backgroundColor": "rgb(67, 56, 202)",
  "foregroundColor": "rgb(255, 255, 255)",
  "labelColor": "rgb(224, 231, 255)",
  "storeCard": {
    "primaryFields": [
      { "key": "balance", "label": "Balance", "value": 12.5, "currencyCode": "USD" }
    ],
    "secondaryFields": [
      { "key": "tier", "label": "Tier", "value": "Gold" }
    ]
  },
  "barcodes": [
    { "format": "PKBarcodeFormatQR", "message": "member-8842", "messageEncoding": "iso-8859-1" }
  ]
}

Dos detalles se escapan siempre. Los colores usan la forma de cadena rgb(r, g, b), no hexadecimal ni un array. Y serialNumber es la identidad del pase: reutilizarlo para otro socio sobrescribe la tarjeta equivocada cuando empujas una actualización.

03Genera el manifest y la firma PKCS#7

La firma es el paso que no se puede simular. Necesitas el certificado Pass Type ID y su clave privada desde tu cuenta de desarrollador, más el certificado intermedio WWDR de Apple.

  1. Calcula el hash de cada archivo salvo el manifest y la firma. Ejecuta esto dentro del directorio del pase:
for f in $(find . -type f ! -name 'manifest.json' ! -name 'signature' -maxdepth 1 | sed 's|^\./||'); do
  printf '  "%s": "%s",\n' "$f" "$(shasum -a 1 "$f" | cut -d' ' -f1)"
done
  1. Monta manifest.json con esas líneas. Debe ser JSON válido y sin coma final tras la última entrada; el bucle anterior deja una coma a propósito, así que quítala o genera el archivo con un script.
  2. Firma el manifest, no los archivos individuales:
openssl smime -binary -sign \
  -certfile WWDR.pem \
  -signer passcert.pem \
  -inkey passkey.pem \
  -in manifest.json \
  -out signature \
  -outform DER
  1. Comprime el directorio sin carpeta padre y sin metadatos de macOS:
zip -r example.pkpass . -x '.*' -x '__MACOSX' -x '.*/'
  1. Verifica antes de publicar. La firma debe validar contra el manifest que realmente empaquetaste:
openssl smime -verify -in signature -inform DER -content manifest.json -noverify

Si ese comando imprime Verification successful, la mitad criptográfica está lista.

04Añade las imágenes con los tamaños que Wallet espera

Wallet escala y después recorta el arte que le das, así que el número que importa es el espacio asignado a cada imagen, medido en puntos. Las imágenes que no encajan en su espacio se escalan y se recortan, y icon.png es obligatorio.

ImagenEspacio asignadoNotas
icon.png29 × 29 puntosObligatorio; también se usa en la pantalla bloqueada y en Mail
logo.png160 × 50 puntosNormalmente más estrecho que el espacio disponible
strip.png375 × 123 puntos375 × 144 para tarjetas de fidelización y cupones, 375 × 98 para entradas de eventos
thumbnail.png90 × 90 puntosMantén la proporción entre 2:3 y 3:2
background.png180 × 220 puntosSe recorta ligeramente por los cuatro lados y se difumina

Un punto equivale exactamente a un píxel en una pantalla no Retina y a dos o tres píxeles en una Retina, así que incluye el archivo base más las variantes @2x y @3x. (Guía de PassKit)

Regenera el manifest al final

Edita las imágenes, luego reconstruye manifest.json, después firma y por último comprime. Cualquier otro orden deja hashes obsoletos y produce un pase que parece terminado pero falla la validación.

05Reglas del código que fallan en silencio

El código es donde el pase deja de ser un ejercicio de diseño. Los escáneres y el software de códigos de barras suelen esperar ISO 8859-1 (Latin-1) o Windows-1252, y la mayoría de los sistemas soporta mal Unicode, así que un message con emoji o con un nombre no latino es el fallo silencioso clásico. Mantén la carga del código en ASCII y pon el texto legible en un campo.

SíntomaCausaSolución
El pase se añade pero el código sale vacíoFalta el array barcodes o está vacíoAñade al menos una entrada con format válido
El código muestra texto corruptomessage no es ISO 8859-1 ni Windows-1252Usa ASCII en message y mueve el texto a un campo
El código no aparece en el Apple WatchSolo hay Code 128, y watchOS no lo admiteAñade una entrada QR o PDF 417 como respaldo
Un iPhone antiguo no muestra el códigoSolo está la clave antigua barcodeEmite también barcodes; el array se usa desde iOS 9

Wallet admite QR, PDF 417, Aztec, Code 128, Code 39, Codabar, EAN 13 e ITF, y PassKit usa la primera entrada compatible del array. QR, PDF 417, Aztec y Code 128 son válidos desde iOS 9, así que esos cuatro no necesitan respaldo. El QR es la opción más segura para el poco espacio que ofrece una pantalla. (Códigos, Guía de PassKit)

Cuanto más corta la carga, mejor

Cada formato tiene un máximo teórico y las condiciones reales de escaneo lo reducen: el ejemplo de la guía es un código en el Apple Watch, con poca luz y un escáner barato. Prueba con el hardware que se usará realmente.

06Prueba en un dispositivo y planifica las actualizaciones

La prueba que documenta Apple es arrastrar el pase a un iPhone del simulador, que muestra el diálogo de añadir si el pase es válido; antes de enviarlo a clientes, recorre el flujo completo de añadir a Wallet en un dispositivo real. Envía el archivo por AirDrop o sírvelo desde HTTPS con el tipo MIME application/vnd.apple.pkpass para que Safari ofrezca el botón de añadir. (Technical Note TN2302)

Si el pase cambia tras emitirse —un saldo, una puerta, una hora de embarque— no lo reconstruyes en el dispositivo. Añades webServiceURL y authenticationToken a pass.json, el dispositivo se registra en tu servidor y entrega un token push, y más tarde tu servidor envía una notificación push que hace que el dispositivo descargue el pase actualizado. Por eso authenticationToken debe ser largo y aleatorio: es el secreto compartido que autentica cada llamada a tus endpoints de actualización.

07Errores comunes y soluciones

ErrorCausa probableSolución
«No se puede añadir el pase», sin detalleEl manifest y la firma no coincidenReconstruye el manifest, firma y comprime de nuevo
La firma valida pero Wallet rechazapassTypeIdentifier no coincide con el certificadoUsa el Pass Type ID exacto del portal
El pase aparece sin estiloColores en hexadecimalUsa cadenas rgb(r, g, b)
La actualización nunca llegaserialNumber erróneo o token caducadoUsa seriales únicos y estables por pase

El patrón tras casi todos los fallos es el mismo: Wallet trata el pase como un artefacto firmado, así que cambiar cualquier byte —incluido volver a guardar una imagen— invalida la firma. Escribe un script que regenere el manifest, firme y comprima en un solo comando y dejarás de depurar hashes a mano.

08Fuentes

Preguntas frecuentes

¿Por qué mi .pkpass no se añade a Apple Wallet?

Nueve de cada diez veces la firma no coincide con el manifest, o el manifest lista un archivo que no está en el ZIP. En ambos casos Wallet rechaza el pase en silencio.

¿Puedo crear un pase de Wallet sin cuenta de desarrollador de Apple?

No. La firma requiere un certificado Pass Type ID emitido desde tu cuenta de desarrollador. Puedes preparar el JSON y las imágenes, pero Wallet no aceptará un pase sin firmar.

¿El manifest usa SHA-1 o SHA-256?

El formato del manifest calcula SHA-1 sobre cada archivo del paquete, algo independiente del debate sobre usar SHA-1 o SHA-256 como hash de objetos en Git.

¿Por qué desaparece el código en el Apple Watch?

watchOS no admite Code 128. Si Code 128 es la única entrada del array barcodes, el reloj no muestra ningún código, así que añade una entrada QR o PDF 417 como respaldo.

¿Por qué no se escanea mi código de barras?

Normalmente la carga no coincide con lo que espera el escáner: el hardware de códigos de barras suele leer ISO 8859-1 o Windows-1252, y soporta mal Unicode. Mantén el message en ASCII y mueve el texto legible a un campo.

Volver a los artículos

Artículos relacionados

Herramientas relacionadas