This is the second part of a two-part tutorial about a new feature in iOS 6 called Passbook. Part 1 of the tutorial, iOS 6 Tutorial: Integrating Passbook into Your Applications is focused on introducing passes and how to create them and interact with them locally on the device.

This tutorial will describe the ecosystem of Passbook, and show you how to generate, deliver, and update passes dynamically. We will also briefly introduce web services that you will need to implement to interact with passes remotely.

What is the Passbook Ecosystem?

Since a pass represents information to display and does not contain any executable code, you must interact with the pass through either a web service or an application you design. There are three players in the Passbook ecosystem; the 1) Conduit App, 2) Companion App, and the 3) Pass Server.

The Conduit

The Conduit App is a delivery mechanism and is most likely an email program, web browser, or another kind of app that allows users to receive and download any pass. The conduit app is expected to display the icon, localized name, and organization name. For instance, this is what an example emailed pass looks like:

Emailed Pass

The Companion

The Companion App allows you to request, modify, and retrieve any pass associated to the application. An example would be an ice cream store's mobile application that can allow a customer to order a dessert online, and add a coupon or membership card pass to the user's library, and update the user's membership rewards card point of sale purchases. Your app can only interact with passes whose pass type identifier matches the app's entitlements.

To programmatically load, access, and modify a pass within an application, you would use the PassKit framework, which provides an Objective-C API for interacting with the user's pass library. If you would like to learn about the PassKit framework and how to use it in your companion app, please read part 1 of this tutorial.

The Server

The Server is the backbone behind the pass ecosystem, it provides the functionality to remotely create, deliver, and update a pass via push notifications.

Passbook was designed to be an independent system-level application on the iPhone. Passes by themselves are useful even if the user doesn't have the companion app installed. A conduit or companion app is not required to use passes in your enterprise since the entire life of a pass can be controlled remotely by your pass server and the Apple Push Notification service (APNs).

Passbook Do's and Don'ts

  • Companion apps should enrich the user experience by doing things that Passbook can't do, such as allowing the user to initiate modifications in the pass like adding a balance to a gift card, changing the seat on a boarding pass or browsing for coupons to save. Additionally, your app should not remove expired passes without the user's consent.
  • You cannot trust the data stored in the pass, instead create a centralized database and trust your database. At the point of redemption, you scan the barcode to pull the unique id and consult your database to determine whether the pass is valid.
  • Similarly, your server needs to keep track of the validity of passes. The pass serial number is used as a record identifier, and the data stored in the pass is just a snapshot.
  • Updates may not be delivered on time, or at all. The user may not have a network connection or may have disabled updates for the pass. Instead, change your database to indicate that the pass has updated, and consult your database at the point of redemption.
  • Expect the recipient of the pass to forward it along to their friends and family. Users with multiple iOS devices can also install the pass on all of their devices. You will be responsible for implementing any "one time use" policies on the server.

In the next couple of sections of this tutorial, we will briefly show you the steps needed to implement a pass web service. The essential steps that the web service will need to do are:

  1. Generate a .pkpass file for the user.
  2. Deliver the pass to the device.
  3. Send an update for the pass to the device.

Generating a .pkpass file

As a refresher from Part 1 of this tutorial, the steps we need to do to create a .pkpass package are:

  1. Generate a pass.json file for the data on the pass
  2. Generate manifest file of package contents
  3. Generate signature file using the pass certificate
  4. Compress folder and rename to .pkpass extension

Presumably your web service will need to generate the pass.json, manifest.json, and signature files. The pass.json file is described in better detail in part 1 of this tutorial. We will focus on generating the manifest.jsonand signature files in this tutorial. Passes are created from a folder containing the following files:

  1. The pass.json, a json dictionary that defines the pass.
  2. Images such as the logo and icon. (background.png, icon.png, strip.png, thumbnail.png)
  3. The manifest.json file, containing a hash of every file in the package.
  4. The signature file, a PKCS#7 signature of the manifest.json file.

The manifest.json file looks like this:

{
 "pass.json" : "de440478cd0db57d35474d88f455e0bcdd0d3864",
 "icon.png" : "ba47a8021c8d74d2146d7244c8a0566be37df43b", 
 "icon@2x.png" : "bd5442b4b08aa4dde333ec9ef0269e7fd93140b3", 
 "logo.png" : "780540b3a324bf66aeaee2d352283371356e9502", 
 "logo@2x.png" : "a718ffd4e611e404dd3eb701454bcaefdabbe311" 
}

The manifest.json file is a JSON dictionary of all the files in the pass package excluding the manifest.json itself and the signature. Each key is a relative path in the pass directory. Each value is the SHA1 hash of the file at that path.

Signing the .pkpass file is done by generating a PKCS#7 detached signature of the manifest.json using the private key associated with the pass certificate and saving it as a file named signature. One important thing to note is that you must include the Apple Worldwide Developer Relations intermediate certificate, downloaded from WWDR, when signing passes. To do this, you will need to export the WWDR certificate as a .pem file from your keychain and determine how to correctly incorporate this certificate depending on your server's pass signing implementation.

Delivering .pkpass file

Now that the server has generated the pass, there are three delivery methods: 1) download via email, 2) download via website, 3) displayed from inside an application.

  1. To deliver a pass via email, you just need to attach the .pkpass file to an email and send it. The Mail app will automatically recognize that the attachment is a .pkpass mimetype and will allow you to add the file to your Passbook. If you have built a conduit application, this can also stand in for the delivery mechanism.
  2. To allow a user to download a pass from a website, declare the MIME type as application/vnd.apple.pkpass and display the pass in a webpage so that Mobile Safari can handle it as a pass.
  3. You can also use the PassKit framework to programmatically load a pass from within a companion mobile application. This framework was introduced in Part 1 of this tutorial, which also explains how to add a pass to the user's Passbook.

Updating the pass card

One thing to remember is that passes are immutable. You cannot modify a pass once it is generated, you must generate a new pass from scratch. There are also no facilities to generate a new pass on the device; you must obtain it from somewhere else such as your web service. The user can request an updated pass using a web service call within a companion application or the web server can dynamically update the pass via a push notification.

Delivery of updates via push notifications requires that you, as a developer, create web services on your server to provide updates to the devices. You must include the following fields in the pass.json, to opt-in to the push notification service.

pass.json: {
 ...
 "webServiceURL" : "https://www.myserver.com/pathto/service",
 "authenticationToken" : "PZ8GL23T24JEB41X6U",
 ...
}

The web service URL is the base for any service endpoints used by Passbook to update the pass. The authentication token is a shared secret between the user's device and your server. This value is generated on your server per pass and shows that the request for an update to a pass is actually coming from a device with the pass. When a device makes a web service request that requires authorization using a passes authentication token, the request header will contain an Authorization field, with the value "ApplePass ".

Updating the pass is a song and dance between three parties – the user's device, Apple's servers, and your servers. Your server implements a RESTful web service protocol that allows this communication to happen. The following services need to be implemented for a pass to be successfully updated by your server.

  1. Device registers for updates
  2. Device asks for all passes associated with it
  3. Device asks for latest version of a pass
  4. Device sends server error logs
Device Registers for Updates

The device registers for updates by sending a POST to the following endpoint, where the payload is a JSON dictionary containing just the push token, and an authorization header is supplied with the pass's authorization token.

 https:////devices/
 /registrations//

Any time the pass is updated, your server needs to send a push notification to the Apple Push Notification service (APNs) with an empty JSON dictionary as the payload. You can implement push notification services on the same server that handles passbook updates, or you can use a third party push notification service like Urban Airship, or Push Woosh. For more information about push notification, please read Apple's Push Notification service documentation.

Device asks for all passes associated with it

The device can periodically ask for all passes with a GET request to the following endpoint:

 https:////devices/
 /registrations/?passesUpdatedSince=

The passesUpdatedSince parameter is an optional argument, similar to the if-modified-since header in an HTTP request. However, the difference is that your web service shall return a collection of serial numbers of passes that have been updated since the timestamp. This value is self defined, and can be any time format that you choose to implement on the server. The server returns a JSON payload with a collection of serial numbers of passes that have updated.

{
 "serialNumbers" : [ , , ... ],
 "lastUpdated" : 
}
Device asks for latest version of a pass

The device can also request an update for a specific pass using the following endpoint, with an authorization header supplied in the request.

 https:////passes/
 /

If the request is authorized, the server shall return HTTP status code 200 with a payload of the pass data signed and compressed in zip format. You can also support the if-modified-since header in the request by responding with Last-modified: in the response header, or HTTP status code 304 if no updates are found.

Device sends server error logs

An optional but highly recommend endpoint to implement is the logging service URL. The server will receive a POST request at the following endpoint, where the payload is a JSON dictionary containing a single key "logs" with an array of strings as the value. The endpoint for posting logs is:

https:////log

Conclusion

This tutorial is the second part of a two part series on Passbook, a newly introduced feature in iOS 6. In this tutorial, we covered the Passbook ecosystem, and the web service APIs required to remotely update a pass. For more information about creating passes or the PassKit framework, please see part 1 of this tutorial.