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:


    • Boarding ticket: by plane or train. Usually the coupon works on one trip;
    • Coupon: for coupons and special offers;
    • Event ticket: can work both for one event, and for the whole season;
    • Discount card: loyalty cards, discount or gift cards;
    • General view of the map: if none of the above does not fit your case: for example, a map for trips to the subway or a pass to the gym.

    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.
    appLaunchURLString URL 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. May have 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 keeper will ask you to enter the password for the certificate. In this case, the password is optional.
    Please note that all further actions should be carried out in the same 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


    opensslpkcs12-incertificates.p12-nocerts-outpasskey.pem-passinpass: -passoutpass:new_password

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


    opensslsmime-binary-sign-certfileWWDR.pem-signerpasscertificate.pem-inkeypasskey.pem-inmanifest.json-outsignature-outformDER-passinpass:пароль_из_предыдущей_команды

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


    zip-rnameOfPass.pkpassmanifest.jsonpass.jsonsignaturelogo.pnglogo@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 a utility signpass( Apple Wallet sample meterials ) that takes care of all the SHA calculations ( manifest.jsonyou can not do the file yourself) and the job of creating signatures. To use it, you need to collect the project and place the file signpassin 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:


    guardlet passPath = Bundle.main.path(forResource: "wallet", ofType: "pkpass") else { return }
            let error: ErrorPointer = ErrorPointer(nilLiteral: ())
            guardlet passData = NSData(contentsOfFile: passPath) else { return }
            let pass = PKPass(data: passData asData, error: error)
            let passLibrary = PKPassLibrary()
            passLibrary.addPasses([pass]) { (status) inprint(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 propose to do it through serialNumber. For example, set as serialNumberuser id or card number.


    Testing


    Apple provides examples of pkpass for different types, you can focus on them.
    Apple Wallet samples
    To see what the map looks like, 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.


    Also popular now: