📜 ⬆️ ⬇️

Apple Wallet. What is it and how to integrate your card into it

It is considered that Wallet is not the most popular service in the CIS. But already in the second project in a row, the customer sets the task “To make integration with the Wallet”. Therefore, I decided to write this article in order to tell about the service as a whole and show how to integrate my product into it.


What is a wallet? It allows you to keep in your phone various types of cards (tickets, discount cards, etc.), making life easier for users of the product. Moreover, it is possible to update the card information via push notifications, but this is a topic for a separate article. But if you have a card / ticket / subscription that can be integrated into the phone, then there is a solution for this! How to do this - read below.


As a rule, your server is responsible for creating the map. The application receives the card in the form of a .pkpass file and already through the application the user can add the card to the Wallet.


Map structure


What is the map from the point of view of the developer? The map is an archive with the .pkpass extension. It contains all the data necessary for the display and operation of the map. The contents of the archive are in the table below.


FilePurpose
background.pngBackground picture for the map.
footer.pngPicture next to the barcode
icon.pngIcon for notifications and letters
logo.pngLogo card. Displayed on the upper left
manifest.jsonRegistry of all included files
signaturePKCS7 signature
pass.jsonAppearance and information on the map
strip.pngPicture behind the main card description
thumbnail.pngAdditional picture (specify)

There are the following types of cards:



Consider schematically the appearance of different cards. Pictures should be called as indicated in the table above.


Boarding card



Coupon



Event ticket



General Map



Discount card



Pass.json structure


Required fields. Contain Pass Type ID, Team ID, organization name, etc.
Keys for related applications. Needed to display applications that need to be "associated" with the map.
Keys "expiration date" cards.
Keys of relevance. For example, the coordinates of the area where the map can be used, or the beginning of the event for which it is intended.
The key is style. At the beginning of the article were listed 5 types of maps for Wallet. Each of them has its own style. Such a key must be strictly one.
Keys visual card design. In addition to the obvious, they contain information about the barcode displayed on the map.
Web service keys. You can use web services to interact with the map, for example, automatically update it.
NFC keys. Contain additional information for Apple Pay transactions.


Now everything is more detailed.


Required fields


JSON keyData typeDescription
descriptionString.
Localizable
Brief map description. Localizable
formatVersionIntFile format version. The value must be 1.
organizationNameString.
Localizable
The name of the organization that issues the cards.
passTypeIdentifierStringPass Type ID and developer cabinet.
serialNumberStringThe serial number of the individual card
teamIdentifierStringTeam ID Developer Team

Keys for related applications


JSON keyData typeDescription
associatedStoreIdentifiers[Int]Optional. Application ID associated with the card. Always take the first, compatible with the current device.
appLaunchURLStringURL that is passed to the application when opened

Style Keys


JSON keyData typeDescription
primaryFields[Json]Basic information about the map.
secondaryFields[Json]Background Information.
auxiliaryFields[Json]Fields for additional information. Optional
headerFields[Json]The title of the card. It is displayed even when the cards are visible in the list.
auxiliaryFields[Json]Basic information about the map.
transitTypeStringType of transport for card tickets. It can take the following values:
PKTransitTypeAir,
PKTransitTypeBoat,
PKTransitTypeBu`,
PKTransitTypeGeneric,
`PKTransitTypeTrain`.
backFields[Json]Array of fields responsible for the back side of the card

JSON in this case has the following form:


"key" : "value1", "label" : "value2", "value" : "value3" 

The value of the key value can be either numeric or string. However, currencyCode together with a string value will not work. As for auxiliaryFields and secondaryFields, there may be several of them, and it is worth monitoring the length of the lines that they use.


Keys of visual design


JSON keyData typeDescription
barcodes[Json]Information for the barcode (see below).
backgroundColorcolor as stringBackground color. (# Fa32e4)
foregroundColorcolor as stringColor labels with values
groupingIdentifierStringOptional for event tickets and transport tickets. Cards with the same style - passTypeIdentifier and groupingIdentifier - will be grouped
labelColorcolor as stringLabel text with field names
logoTextLocalizable stringText displayed next to the logo

Barcode


The most important part of the map. The identification number of the card is sewn into it (for example, the physical card number or the ticket number). It is important that a scanner or any other tool be able to read codes in the proper encoding.


JSON keyData typeDescription
altTextStringOptional text displayed next to the barcode if the barcode is not readable.
formatStringBarcode format. May take values: PKBarcodeFormatQR,
PKBarcodeFormatPDF417,
PKBarcodeFormatAztec,
PKBarcodeFormatCode128
messageStringCode or card number encrypted in barcode.
messageEncodingStringMessage encoding Usually iso-8859-1

Location


These keys are responsible for the location within which the map can be used.


JSON keyData typeDescription
altitureStringOptional text displayed next to the barcode if the barcode is not readable.
latitudeLongitudeLatitude
longtitudeDoubleLatitude
relevantTextStringOptional text that is displayed on the lock screen when the user enters the range of the card.

Downside


Additional information can be placed on the reverse information part: terms of use, auto-update policy, contact details and a link to the application to which the card belongs. The figure shows the correspondence of the fields in pass.json and the appearance of the back side of the map. If the value-field has links, phone numbers, etc., they will be highlighted automatically.



Create a map. Part 2


So, the pictures are ready, pass.json is formed, it remains to put all this together. To do this, fill in manifest.json (see table 1), where you need to include all the pictures and pass.json. It turns out like this:


 . . . . . . "pass.json" = 303c753abc39aa732ec74643d6db28348fe8a823; "strip.png" = 736d01f84cb73d06e8a9932e43076d68f19461ff; "strip@2x.png" = 468fa7bc93e6b55342b56fda09bdce7c829d7d46; . . . . . . 

From this point on it is not necessary to change anything, since SHA will be incorrect, in case of changes, it is necessary to generate SHA again.


Next you need to create a Pass Type ID in the developer’s office and make a certificate for it. The procedure should be more or less familiar if you have previously created, for example, Provisioning profiles.



Then we go to the key-keeper (Keychain) and export the Apple Worldwide Developer Relation Certificate (WWDR) from there as .pem.



From there, we export the created Pass Type ID as .p12. At this stage, the key card asks you to enter the password for the certificate. In this case, the password is optional.
Please note that all further actions should be performed in one folder where manifest.json, pass.json and pictures should already be located.


Now you need to generate a signature, which we will sign the archive. To begin with, export the Pass Type ID and the key to it as .pem.


 openssl pkcs12 -in certificate.p12 -clcerts -nokeys -out passcertificate.pem -passin pass: your_password 

and


 openssl pkcs12 -in certificates.p12 -nocerts -out passkey.pem -passin pass: -passout pass:new_password 

Now we are ready to generate a signature. Make this a command:


 openssl smime -binary -sign -certfile WWDR.pem -signer passcertificate.pem -inkey passkey.pem -in manifest.json -out signature -outform DER -passin pass:___ 

So, everything is ready with us, it remains only to collect the archive, we do it with the command:


 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 

I draw your attention to the fact that all the files to which you want to include the data archive for the card (.pkpass) should be listed here.
As a result, we get a .pkpass file that can be opened on the computer. We will see a preview of the map, the appearance of which may differ from the appearance on the phone.
All this can be done a little easier. Apple provides the signpass utility ( Apple Wallet sample meterials ), which takes all the SHA calculations (the manifest.json file can be left alone) and the work of creating signatures. To use it, you need to collect the project and place the signpass file in a folder with all the necessary resources.



In general, the structure should look like this:



Next, execute the command:


 ./signpass -p wallet 

Wallet is the name of the folder in which all resources lie. At the output we get the file wallet.pkpass. Its contents can be viewed by unarchiving wallet.pkpass.


 unzip wallet.pkpass 

It is possible that the creation of pkpass will be put on the backend, in this case it will be necessary to transfer to the developers of WWDR, ​​a certificate for the Pass Type ID in the form of .p12 and a password for it.


Application Integration


In order for the app to have the ability to add maps to the Wallet, you must enable this feature in the App ID and also enable this feature in the Capabilities in the project.




This is necessary for full-fledged correct work with Wallet. Otherwise, it will not be possible to read cards from the Wallet and, for example, it will not be possible to understand whether our card has been added or not. It is also important to note that the team id in pass.json must match the c team id, or you will have to add them manually to the entitlements and this may correct the situation, but I did not check it.



Adding a card


Adding cards is very 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)) } 

However, again, more often .pkpass file will need to be downloaded from your server.
It is worth noting that PassKit gives quite readable errors, so you can easily understand what exactly was done wrong.


Getting information about added maps


To get information about the maps available in the Wallet and related to your application, you need to refer to the PKPassLibrary object.


 let passLibrary = PKPassLibrary() let passes = passLibrary.passes() 

Thus, it is possible to understand whether a map has been added or not, as well as to update the interface. In addition, through the PKPassLibrary maps can be updated and deleted. You can update maps via web services, but in this article we will not consider this option.


Check for uniqueness


Since in your service, as a rule, the card is tied to an account, the application will most likely have to somehow determine whether the card belongs to the current user. I suggest doing this through serialNumber . For example, set the user ID or card number as the serialNumber .


Testing


Apple provides examples of pkpass for different types, you can focus on them.
Apple Wallet samples
To see how the map looks, you can add pkpass to the project (see “Adding a Map”). The process of adding / deleting has already been discussed above, it remains only to remind that the application will not see already added cards, if the card for Wallet was created on one developer account, and the development itself was carried out from another account (relevant for outsourcing companies). In this case, you can add cards without problems.
You can check whether the information in the barcode is correctly encoded using any QR code scanner. And just need to check the correctness of the work with this scanner.


Conclusion


The article reviewed the process of creating and designing the card, as well as the process of integration with the application and the problems that may arise. I deliberately did not address the issues of integration with web services and map updates, and I hope to do this in the next article.


Materials used:


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


Special thanks to mehdzor for the developer account for tests.


')

Source: https://habr.com/ru/post/428437/


All Articles