É geralmente aceito que o Wallet não é o serviço mais popular na CEI. Mas já no segundo projeto consecutivo, o cliente define a tarefa "Tornar a integração com o Wallet". Portanto, decidi escrever este artigo para falar sobre o serviço como um todo e mostrar como integrar meu produto a ele.
O que é uma carteira? Ele permite que você mantenha vários tipos de cartões em seu telefone (ingressos, cartões de desconto etc.), facilitando a vida dos usuários do produto. Além disso, é possível atualizar informações sobre o mapa por meio de notificações push, mas este é um tópico para um artigo separado. Mas se você possui um cartão / ticket / assinatura que pode ser integrado ao telefone, existe uma solução! Como fazê-lo - leia abaixo.
Como regra, seu servidor é responsável por criar o mapa. O aplicativo recebe o cartão na forma de um arquivo .pkpass e, por meio do aplicativo, o usuário pode adicionar o cartão à Carteira virtual.
Estrutura do mapa
Qual é o mapa do ponto de vista do desenvolvedor? Um mapa é um arquivo com a extensão .pkpass. Ele contém todos os dados necessários para a exibição e operação do cartão. O conteúdo do arquivo está na tabela abaixo.
Ficheiro | Nomeação |
---|
background.png | Imagem de fundo para o cartão. |
footer.png | Imagem ao lado do código de barras |
icon.png | Ícone para notificações e cartas |
logo.png | Logotipo do cartão Superior esquerdo exibido |
manifest.json | Registro de todos os arquivos incluídos |
assinatura | Assinatura PKCS7 |
pass.json | Informações sobre aparência e mapa |
strip.png | Imagem localizada atrás da descrição principal do cartão |
thumbnail.png | Imagem adicional (especifique) |
Os seguintes tipos de cartões estão disponíveis:
- Bilhete de embarque: de avião ou trem. Normalmente, o cupom funciona para uma viagem;
- Cupom: para cupons e ofertas especiais;
- Bilhete de evento: pode funcionar tanto para um evento quanto para uma temporada inteira;
- Cartão de desconto: cartões de fidelidade, cartões de desconto ou presente;
- Cartão de visão geral: se nenhuma das opções acima se aplica ao seu caso: por exemplo, um cartão para viajar de metrô ou um passe para a academia.
Considere esquematicamente a aparência de diferentes cartões. As fotos são melhor nomeadas, conforme indicado na tabela acima.
Cartão de embarque

Cupão

Bilhete de Evento

Cartão comunitário

Cartão de desconto

Estrutura Pass.json
Campos obrigatórios. Contém ID do tipo de passe, ID da equipe, nome da organização etc.
Chaves para aplicativos relacionados. Necessário para exibir aplicativos que precisam ser "associados" ao mapa.
Tecla cartões "data de validade".
Chaves de relevância. Por exemplo, as coordenadas da área em que o mapa pode ser usado ou o início do evento a que se destina.
A chave é o estilo. No início do artigo, foram listados 5 tipos de cartões para o Wallet. Cada um deles tem seu próprio estilo. Essa chave deve ser estritamente uma.
Teclas para o design visual do cartão. Além do óbvio, eles contêm informações sobre o código de barras exibido no mapa.
Chaves de serviço da Web. Você pode usar serviços da web para interagir com o mapa, por exemplo, atualizá-lo automaticamente.
Teclas NFC. Contém informações adicionais para transações do Apple Pay.
Agora, sobre tudo em mais detalhes.
Campos obrigatórios
Chave em JSON | Tipo de dados | Descrição do produto |
---|
descrição | String Localizada | Uma breve descrição do mapa. Localizado. |
formatVersion | Int | Versão em formato de arquivo. O valor deve ser 1. |
organizationName | String Localizada | O nome da organização que emite os cartões. |
passTypeIdentifier | String | Passe o ID do tipo e a conta de desenvolvedor. |
serialNumber | String | Número de série do cartão único |
teamIdentifier | String | ID da equipe de desenvolvimento |
Chaves para aplicativos relacionados
Chave em JSON | Tipo de dados | Descrição do produto |
---|
AssociatedStoreIdentifiers | [Int] | Opcionalmente. O ID dos aplicativos associados ao cartão. O primeiro que é compatível com o dispositivo atual é sempre utilizado. |
appLaunchURL | String | URL que é passado para o aplicativo na abertura |
Teclas de estilo
Chave em JSON | Tipo de dados | Descrição do produto |
---|
primaryFields | [JSON] | Informações básicas sobre o mapa. |
campos secundários | [JSON] | Informações básicas. |
auxiliarryFields | [JSON] | Campos para informações adicionais. Opcional |
headerFields | [JSON] | O título do mapa. É exibido mesmo quando os cartões estão visíveis na lista. |
auxiliarryFields | [JSON] | Informações básicas sobre o mapa. |
transitType | String | Tipo de transporte para cartões de passagem. Pode levar os seguintes valores: PKTransitTypeAir, PKTransitTypeBoat, PKTransitTypeBu`, PKTransitTypeGeneric, `PKTransitTypeTrain`. |
backFields | [JSON] | Matriz de campos responsáveis pelo verso do mapa |
JSON, neste caso, tem o seguinte formato:
"key" : "value1", "label" : "value2", "value" : "value3"
O valor pela chave do valor pode ser numérico ou sequência. No entanto, currencyCode junto com o valor da sequência não podem ser usados. Quanto aos campos auxiliares e campos secundários, pode haver vários deles, e você deve monitorar o comprimento das linhas que são usadas neles.
Teclas para Design Visual
Chave em JSON | Tipo de dados | Descrição do produto |
---|
códigos de barras | [JSON] | Informações para o código de barras (veja abaixo). |
backgroundColor | cor como string | Cor do plano de fundo. (# Fa32e4) |
primeiro planoColor | cor como string | Cor da etiqueta com valores |
groupingIdentifier | String | Opcional para bilhetes para eventos e bilhetes de transporte. Cartões com o mesmo estilo - passTypeIdentifier e groupingIdentifier - serão agrupados |
labelColor | cor como string | Rótulo de texto com nomes de campo |
logoText | String localizável | Texto exibido ao lado do logotipo |
Código de barras
A parte mais importante do mapa. Um número de identificação do cartão é costurado nele (por exemplo, um número do cartão físico ou um número do bilhete). É importante que o scanner ou qualquer outra ferramenta possa ler códigos na codificação correta.
Chave em JSON | Tipo de dados | Descrição do produto |
---|
altText | String | Texto opcional exibido ao lado do código de barras se o código de barras não for lido. |
formato | String | Formato de código de barras. Pode assumir valores: PKBarcodeFormatQR, PKBarcodeFormatPDF417, PKBarcodeFormatAztec, PKBarcodeFormatCode128 |
mensagem | String | Código ou número do cartão criptografado em código de barras. |
messageEncoding | String | Codificação de mensagem. Geralmente iso-8859-1 |
Localização
Essas chaves são responsáveis pelo local em que o cartão pode ser usado.
Chave em JSON | Tipo de dados | Descrição do produto |
---|
altiture | String | Texto opcional exibido ao lado do código de barras se o código de barras não for lido. |
latitude | Longitude | Latitude |
longitude | Duplo | Latitude |
relevantesTexto | String | Texto opcional que aparece na tela de bloqueio no momento em que o usuário digita o intervalo do cartão. |
Lado traseiro
Informações adicionais podem ser colocadas na parte reversa das informações: termos de uso, política de atualização automática, detalhes de contato e um link para o aplicativo ao qual o cartão pertence. A figura mostra a correspondência dos campos em pass.json e a aparência do verso do mapa. Se houver links, números de telefone etc. no campo de valor, eles serão destacados automaticamente.

Crie um mapa. Parte 2
Assim, as fotos estão prontas, o pass.json é formado, resta reunir tudo. Para fazer isso, preencha manifest.json (consulte a tabela 1), onde você precisa incluir todas as imagens e pass.json. Acontece algo como isto:
. . . . . . "pass.json" = 303c753abc39aa732ec74643d6db28348fe8a823; "strip.png" = 736d01f84cb73d06e8a9932e43076d68f19461ff; "strip@2x.png" = 468fa7bc93e6b55342b56fda09bdce7c829d7d46; . . . . . .
A partir deste momento, nada precisa ser alterado, pois o SHA estará incorreto; em caso de alterações, é necessário regenerar o SHA.
Em seguida, você precisa criar um ID do tipo de passe no escritório do desenvolvedor e fazer um certificado para ele. O procedimento deve ser mais ou menos familiar se você tiver criado anteriormente, por exemplo, perfis de provisionamento.

Em seguida, vá para o Keychain e exporte dali o Apple Worldwide Developer Relation Certificate (WWDR) como .pem.

A partir daí, exportamos o código do tipo de passagem criado como .p12. Nesse momento, a governanta solicitará que você digite a senha do certificado. Nesse caso, uma senha é opcional.
Observe que todas as ações adicionais devem ser executadas em uma pasta, onde manifest.json, pass.json e imagens já devem estar.
Agora você precisa gerar uma assinatura, a qual assinaremos o arquivo. Primeiro, exporte o ID do tipo de passe e a chave para ele como .pem.
openssl pkcs12 -in certificate.p12 -clcerts -nokeys -out passcertificate.pem -passin pass: your_password
e
openssl pkcs12 -in certificates.p12 -nocerts -out passkey.pem -passin pass: -passout pass:new_password
Agora estamos prontos para gerar uma assinatura. Vamos fazer um comando:
openssl smime -binary -sign -certfile WWDR.pem -signer passcertificate.pem -inkey passkey.pem -in manifest.json -out signature -outform DER -passin pass:___
Então, está tudo pronto para nós, resta apenas coletar o arquivo, fazemos isso com o 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
Chamo a atenção para o fato de que todos os arquivos nos quais você deseja incluir o arquivo de dados do cartão (.pkpass) devem ser listados aqui.
Como resultado, obtemos um arquivo .pkpass que pode ser aberto no computador. Veremos uma prévia do cartão, cuja aparência pode diferir da aparência do telefone.
Tudo isso pode ser feito um pouco mais fácil. A Apple fornece o utilitário signpass
( signpass
amostra da Apple Wallet ), que cuida de todos os cálculos do SHA (o arquivo manifest.json
pode ser deixado sozinho) e do trabalho de criação de assinaturas. Para usá-lo, você precisa criar um projeto e colocar o arquivo signpass
em uma pasta com todos os recursos necessários.

Em geral, a estrutura deve se parecer com isso:

Em seguida, execute o comando:
./signpass -p wallet
Carteira é o nome da pasta na qual todos os recursos estão localizados. A saída é wallet.pkpass. Seu conteúdo pode ser visualizado descompactando wallet.pkpass.
unzip wallet.pkpass
É possível que a criação do pkpass seja enviada ao back-end; nesse caso, será necessário transferir para os desenvolvedores do WWDR o certificado para a identificação do tipo de passe na forma de .p12 e a senha para ele.
Integração de aplicativos
Para que o aplicativo possa adicionar cartões à Carteira virtual, você deve habilitar esse recurso no ID do aplicativo e também esse recurso em Recursos no projeto.


Isso é necessário para o trabalho correto completo com a Carteira virtual. Caso contrário, não será possível ler cartões da Carteira virtual e, por exemplo, não será possível entender se nosso cartão foi adicionado ou não. Também é importante observar que o ID da equipe no pass.json deve corresponder ao ID da equipe ou você deve adicioná-los manualmente aos direitos e isso pode corrigir a situação, mas não verifiquei isso.

Adicionando um cartão
Adicionar mapas é muito simples:
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)) }
No entanto, mais uma vez, é mais necessário baixar o arquivo .pkpass do seu servidor.
Vale ressaltar que o PassKit produz erros razoavelmente legíveis, para que você possa entender facilmente o que exatamente foi feito de errado.
Para obter informações sobre os cartões disponíveis no Wallet e relacionados ao seu aplicativo, você precisa acessar o objeto PKPassLibrary.
let passLibrary = PKPassLibrary() let passes = passLibrary.passes()
Assim, você pode entender se o mapa foi adicionado ou não, além de atualizar a interface. Além disso, os mapas da PKPassLibrary podem ser atualizados e excluídos. Os mapas também podem ser atualizados via serviços da Web, mas neste artigo não consideraremos essa opção.
Verificação de exclusividade
Como em seu serviço, como regra geral, o cartão está vinculado a uma conta, no aplicativo é mais provável que você precise determinar de alguma forma se o cartão pertence ao usuário atual. Eu sugiro fazer isso através de serialNumber
. Por exemplo, defina a identificação serialNumber
do usuário ou número do cartão.
Teste
A Apple fornece exemplos de pkpass para diferentes tipos, você pode se concentrar neles.
Amostras de carteira da Apple
Para ver como é o mapa, você pode adicionar o pkpass ao projeto (consulte “Adicionando um mapa”). O processo de adição / remoção já foi discutido acima, resta apenas lembrar que o aplicativo não verá os cartões já adicionados se o cartão da Carteira virtual for criado na conta de um desenvolvedor e o próprio desenvolvimento foi realizado a partir de outra conta (relevante para empresas de terceirização). Nesse caso, você pode adicionar cartões sem problemas.
Você pode verificar se as informações no código de barras estão codificadas corretamente usando qualquer scanner de código QR. E é definitivamente necessário verificar a correção do trabalho com este scanner.
Conclusão
O artigo examinou o processo de criação e design de um mapa, bem como o processo de integração com o aplicativo e os problemas que possam surgir. Intencionalmente, não resolvi problemas de integração com serviços da Web e atualizações de mapas, e espero fazer isso no próximo artigo.
Materiais 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
Agradecimentos especiais a mehdzor pela conta do desenvolvedor para os testes.