Interacting with Passes in Your App

There are two main reasons apps interact with passes: to provide an integrated user experience or to serve as a conduit for passes. An event venue’s app is an example of an integrated user experience. This app could show the performance schedule, play short video clips, and let users buy tickets. After buying a ticket, it could add a pass for that ticket to Passbook and create an event in the user’s calendar. It could also include UI for managing the tickets that users have purchased. An email or instant messaging client is an example of an app serving as a conduit. Just as it supports attachments such as images, it could also support passes attached to a message like Mail does. The app could display UI that indicated that the message has a pass attached and allow users to add the pass to their library. Supporting passes in your app should add value for the user; avoid trying to duplicate functionality of the Passbook app.

Your app needs the appropriate entitlements to read, update, or delete passes. Adding a pass requires explicit user interaction, so it doesn’t require an entitlement. You use Xcode to turn on entitlements. The entitlement specifies the pass type identifiers that your app can interact with. If your provisioning profile is associated with multiple pass type identifiers, you can specify which ones you want.

The Pass Kit framework provides model-level access to pass data. The PKPassLibrary class represents the pass library, and the PKPass class represents individual passes. The framework also provides a view controller, the PKAddPassesViewController class, which displays a pass and lets users add it to their pass library. Your app is responsible for the views it needs to display passes. To present a pass, use the passURL property of a pass to show it in Passbook:

[[UIApplication sharedApplication] openURL:[pass passURL]]

Checking Whether the Pass Library Is Available

The presence of the Pass Kit framework and its classes doesn’t mean that the pass library is available. To check for its availability, call the isPassLibraryAvailable method of the PKPassLibrary class.

Checking Whether a Pass Is in the Library

You can determine whether a pass is in the library even if you don’t have the entitlement to actually read the pass. This allows apps that act as conduits for passes to display the appropriate UI: for passes that are already in Passbook, an indication that they have been added, and for other passes an affordance to add them to Passbook.

To check whether a pass is in the library:

  1. Create an instance of the PKPass class for the pass.

  2. Create an instance of the PKPassLibrary class.

  3. Call the containsPass: method of the PKPassLibrary class with the pass you just created.

Getting Passes

Use the passes method of the PKPassLibrary class to get all passes that your app is entitled to access. Passes are returned in an arbitrary order. If your app displays a list of passes, it should sort them in some meaningful way such as by date.

To receive notifications when the pass library changes, register for the PKPassLibraryDidChangeNotification notification. Pass the instance of PKPassLibrary as the object. The pass library isn’t a singleton; each instance sends its own notifications, and you want the notifications from this particular instance. Use the addObserverForName:object:queue:usingBlock: method to specify that you want to respond on the main queue and provide a block to handle the notification. The user info dictionary of the notification describes what changed. Alternately, use the dispatch_async and dispatch_get_main_queue functions to respond on the main thread.

Reading a Pass

Use the passWithPassTypeIdentifier:serialNumber: method of the PKPassLibrary class to read a particular pass from the pass library.

You can access certain common bits of data, such as the organization name and description, using the properties of the PKPass class. You can access the description using the localizedDescription method. These are useful if your app is acting as a conduit passes that you didn’t create, so you don’t know their fields’ keys.

You can access specific fields of a pass using the their key with the localizedValueForFieldKey: method. This is useful if you created the pass, because then you know the keys for specific fields.

Adding a New Pass

To add a pass to the library:

  1. Create an instance of the PKPass class for the pass, initializing it with the pass’s data.

  2. Use the containsPass: method of the PKPassLibrary class to check whether the pass is in the library. Your app can use this method to detect the presence of a pass, even if it doesn’t have the entitlements to read passes in the library.

  3. If the pass isn’t in the library, use an instance of the PKAddPassesViewController class to let the user add it.

    Present the add passes view controller modally, with animation.

Changing a Pass

Passes cannot be changed directly on the device. Changing the contents of a pass would invalidate its signature. An updated pass needs to be signed using your private key, and distributing your private key as part of your app would be a particularly poor security practice.

To change a pass, coordinate with your server:

  1. Your app connects to your server. It identifies the pass by serial number and pass type identifier and describes the change to your server.

  2. Your server updates your business records as needed, creates a new version of the pass, and signs it.

  3. Your app downloads the new pass from your server and uses the replacePassWithPass: method of the PKPassLibrary class to install it.

After creating a new version of the pass, your server should also send a push notification so that other devices with this pass installed will get the latest copy.

Removing a Pass

Use the removePass: method of the PKPassLibrary class to remove a pass.

Remember that passes belong to the user, not to your app. Pass removal should be done only in response to a direct user action. Never remove a pass without the user’s consent, even if the pass is expired or outdated.