Apple’s simplified explanation of passes is that they are “everything in your pocket.” I like that line very much, because it demonstrates so well how imaginative you can and should be about creating your pass applications and services. Passes can be anything.
“But what are they, anyway?”, you might ask.
Well, here’s how a pass looks on the iPhone:
You can easily spot a few different elements on the front of this pass that give you important information: a logo and a company name on the top, the words “Free hug!”, which clearly denote what this pass is all about, and also information concerning its validity (start date, duration).
Then there’s that barcode at the bottom. It’s much like the barcodes you’re already used to seeing on train tickets, airplane boarding passes, store cards, etc. If you think about it, a pass on your iPhone can carry the same information as any of those paper passes you are used to stuffing in your pockets, right? Some text, a barcode – and that’s it. Trust me, though: a digital pass on your iPhone can also do a lot more.
What makes a pass, a pass
Look again at what’s on the pass below and consider the different sections it has:
All types of passes have these important areas in common:
- Top header. A top ribbon containing an easy-to-identify logo and a company name. This header area is the part of the pass a user will see when they open a full deck of passes in Passbook. It includes the most essential info you want to provide to the user, so they can easily spot the pass they need.
- Main content area. A section containing the substance of the pass. Each pass type has different styling for this section, and it usually shows the information that you want most prominently displayed once the pass is open. It’s very useful for labels like “20% off,” “One free coffee,” “Balance: $120” or anything else of the sort.
- Additional info. The third section is for additional information – material that’s still very important (the validity of the promotion and the start date in the example), but definitely not as important as what the pass is all about.
- Barcode. The barcode contains encoded information that can be easily transferred to other systems by scanning it with a barcode reader. In the example above, the barcode contains a secret code. When decoded by a scanner, it entitles the bearer of the pass to one free hug (to be delivered immediately).
By now you’re probably considering which of the paper passes, store cards, etc. that you use on a daily basis can be converted to a digital pass on your iPhone!
Do I board with this pass, or do I get a free coffee?
Before you dive into coding, have a look at the different types of passes.
Apple has defined four types of passes, each for a common use, as well as a fifth type for “generic” use. Why these different pass types, and how do you recognize them?
The pre-defined pass types are each styled to draw attention to different pieces of information that suit the purpose of the pass. There’s a reason why the layout and content of your gym membership card is different from your concert ticket! The first needs your picture on it while the second doesn’t, for example.
Layout is the main way to differentiate between passes, but UI features like rounded corners and paper cutouts also make passes easily distinguishable. The differences are small, but noticeable, and that’s one of the reasons you have to make sure you use the correct type for your pass.
Here are the four pre-defined pass types:
- Coupon
- Boarding pass
- Store card
- Event ticket
Then of course, there is the generic type of pass. This tutorial will cover all five types in detail in Part 2.
For now, have a look at the boarding pass example below. You can see it’s pretty similar to the hug coupon from earlier, but has some important differences: it features a great two-column layout that makes it very easy to spot the departure and arrival cities; the departure platform number, time and seat number are also well-placed.
By now I am sure you are convinced that passes are a great thing for the iPhone! Now let’s turn to how passes are set up, and how to make one!
The guts of the pass
This section will introduce the building blocks for a pass. A pass comes to the user as a file with a .pkpass extension. (“pkpass” standing for PassKit Pass – totally makes sense, right?)
The .pkpass file is just an ordinary .zip file with a custom extension. If you rename one to ZIP and extract it, you’ll find several files. Here are the contents of the Free Hug Pass you saw earlier:
- pass.json – the description of the pass information fields, their content, and meta information.
- manifest.json – the file that describes the list of files inside the pass and the SHA1 checksums of each of those files.
- signature – a detached DER signature of manifest.json, generated using an Apple-provided certificate.
- background.png – the image to show on the front of the pass.
- background@2x.png – the retina-sized image for the front of the pass.
- logo.png – the logo to show in the pass header. Apple recommends a solid one-color logo. The image size is up to you, but the height shouldn’t be more than 50px in order to fit inside the header.
- logo@2x.png – the retina counterpart of logo.png.
- icon.png – a small icon for the pass, used when the pass comes as an attachment in Mail. As of the time of writing, there is still no documentation about the icon’s size, but it looks to be 29×29 pixels (bigger size icons are scaled down, so they look fine as well).
- icon@2x.png – the retina icon file.
- strip.png and strip@2x.png – the image strip, used as background behind the primary fields; used only for the coupon and store card passes.
And that’s all!
As you can see, the main file of the pass is the JSON file pass.json. Inside it you declare all the contents of the front and back of the pass. Along with this JSON file, you provide all images the pass should display (in the case of a coupon, you can supply only background.png and its retina counterpart). Finally, you need a manifest file, which states the original SHA1 checksums of all those files above, and a detached signature signed by you, so that Passbook can verify that the pass hasn’t been amended since you created it.
Let’s write some JSON!
You’re at the point where you can write some code. Let’s see if you can reproduce the Free Hug coupon!
But wait! JSON isn’t Objective-C. It’s not even a programming language of any sort. It’s just a markup language used to describe data structures… So, how do you write JSON? Actually, you can use any text editor – Xcode, TextMate, Coda or even TextEdit. In this chapter, you’re going to use Xcode.
From Xcode’s menu choose File/New/File… and then choose iOS/Other/Empty for the file type. Name the new file pass.json and save it in a folder of your choice. Note you probably want to create a new folder to store the pass in, because you’ll be putting a lot of pass-related files in the same folder and it will be nice to keep it all together.
You should now be looking at a tragically empty window, like this one:
But’s that’s OK – no worries!
For those of you not familiar with JSON notation – it’s pretty easy. You can use numbers, strings, arrays, and dictionaries. The information is written out like this:
14.37457 – for numbers
“Some text here!” – for strings
[object1, object2, object3, …] – for arrays
|
And:
{“key1”: object1, “key2”: object2, “key3”: object3, …} – for dictionaries
|
Object1, object2, object3 and so forth can be any of the four types of objects above – i.e. you can have arrays of dictionaries, dictionaries that hold arrays, strings, numbers, and so on.
Let’s start with the barebones of the Free Hug coupon! Copy this code into your pass.jsonfile:
{
"formatVersion" : 1,
"passTypeIdentifier" : "pass.com.yourdomain.couponfreehug",
"serialNumber" : "001",
"teamIdentifier" : "<YOUR TEAM IDENTIFIER>",
"organizationName" : "Free Hugs LLC",
"description" : "Coupon for 1 Free Hug"
}
|
This is the bare minimum of meta-information you need to provide:
- formatVersion – the file format version, and since this is a brand-new file format, you’re using 1 (note that 1 is a number; if you provide a string for the value, the file won’t validate).
- passTypeIdentifier – this is the identifier of the Pass. It’s pretty similar to the bundle identifier in an iOS app. More will be said about this identifier in a minute.
- serialNumber – this is the serial number of the pass. You generate this number any way you like – it can be numeric, like “00193” (note that it still needs to be written out as a string value), or a combination of letters and numbers, like the serial numbers you’ve seen on airplane boarding passes (for example, “XS83A”).
- teamIdentifier – this is the unique 10-character identifier Apple assigns to you as an iOS developer. If you’ve been creating your own iOS apps, you should already be familiar with it. To find your team identifier, log onto the iOS Member Center and click the name of your organization. You will find it there next to a label titled “Company/Organization ID”. I’ll show you another way to find it later on as well.
- organizationName – the name of the issuing entity.
- description – a short description of the pass.
This is a lot of information, so let’s see how is it useful to Apple.
Since the passes are not necessarily connected to an iOS app, there’s no automatic way for Apple to connect a pass to a given iOS developer account (which it needs to do to validate the pass contents). Passes might arrive to the user’s device independent from an app, via mail or web download (or another way). This is why the teamIdentifier is included in the meta information inside the pass – to connect the pass instance to an iOS developer.
Once Apple knows the identity of the developer who created the pass, they take the passTypeIdentifier to figure out which type of pass it is (of all the ones defined by a given developer account). Every pass type has its own certificate, so Apple can use this certificate and validate the signature included in the pass bundle – i.e., make sure nobody tampered with the pass contents.
Finally, the serial number is used to identify the unique instance issued for the given pass type.
To recap, consider an example:
- Joe’s Café has an iOS developer account with Apple. Thus, they use their team identifier on all their passes.
- They have store cards with preloaded store credit, which users can use to order yummy coffees in the shop. Store cards have passTypeIdentifier “pass.com.joescafe.storeCard”.
- They also have discount coupons that have a different passTypeIdentifier – “pass.com.joescafe.discountCoupon”.
- A given user can own more than one store card (for example, they bought one and a friend gave them one as a present), so the serial number is used to distinguish between two store cards of the same pass type (for example, “0134” and “0274”).
- Passes from the same passTypeIdentifier will be grouped together inside Passbook. When the user is at Joe’s Café, they’ll tap the stack of Joe’s Café store cards in Passbook, and choose the one they want to use – probably the one that still has credit on it!
By now you should understand pretty well how pass identification works. So “pass” this section and move on to the next, where you’ll create your first pass type.
Get me the certificate!
If you’ve already been checking out the new stuff for iOS 6, you might have noticed the new item in the left menu called Pass Type IDs. Click on that link and on the next page, you’ll see a list of all the pass types you’ve already created (probably empty at this point).
Click the New Pass Type ID button and you’ll go to a page where you can create a new type. In the description field enter “Free Hug Pass” and in the Identifier field enter “pass.com.yourdomain.couponfreehug”. For the Pass Type ID, Apple recommends the reversed domain notation with a prefix of “pass.” So that’s the format you’re using.
Note: For the purposes of this chapter you can certainly use “com.yourdomain”, but in production applications remember that you should replace com.yourdomain with the actual reverse notation for your domain. ☺
Also note that if you decide to change the identifier here to something other than “pass.com.yourdomain.couponfreehug”, you’ll also have to update the passTypeIdentifier value in pass.json accordingly.
Next, simply click Submit to create your pass.
By the very way that light indicator is not lit up in green, you might already guess there’s something missing. Yes – you are right. You still need to generate the pass certificates. Click on Configure to do that. The next page that comes up is a good place to spot the full identifier of your pass.
Here you can see your teamIdentifier (it’s the first 10 characters beginning with ABC) and update pass.json with it – make sure to replace only the placeholder and leave the quotes around it!
All right! Your pass.json metadata is now updated. However, there’s still an extra step to get your certificate imported into your development environment.
Back in the iOS Provisioning Portal, click the Configure button:
This will launch the Pass Certificate Assistant (*fancy name!), which will guide you through the process of generating your certificate. Pay attention to the dialog and follow the steps.
After you upload your signing request, your certificate will be generated in a timely manner and you should see the success dialogue:
Click Continue one more time and then click Download to get the certificate file. After the file downloads, find and double click it to import it into the Keychain. Note that it’s most probably in the Downloads folder inside your user folder, unless you’ve set another default download location in your browser.
If Keychain asks you to confirm the import, click the Add button:
And then you should see your certificate in Keychain Access:
w00t – you’re done making your certificate! Now you have real metadata in your JSON file and the proper certificate for when the time comes to sign the pass.
{
"formatVersion" : 1,
"passTypeIdentifier" : "pass.com.yourdomain.couponfreehug",
"serialNumber" : "001",
"teamIdentifier" : "<YOUR TEAM IDENTIFIER>",
"organizationName" : "Free Hugs LLC",
"description" : "Coupon for 1 Free Hug"
}
|
This is the bare minimum of meta-information you need to provide:
- formatVersion – the file format version, and since this is a brand-new file format, you’re using 1 (note that 1 is a number; if you provide a string for the value, the file won’t validate).
- passTypeIdentifier – this is the identifier of the Pass. It’s pretty similar to the bundle identifier in an iOS app. More will be said about this identifier in a minute.
- serialNumber – this is the serial number of the pass. You generate this number any way you like – it can be numeric, like “00193” (note that it still needs to be written out as a string value), or a combination of letters and numbers, like the serial numbers you’ve seen on airplane boarding passes (for example, “XS83A”).
- teamIdentifier – this is the unique 10-character identifier Apple assigns to you as an iOS developer. If you’ve been creating your own iOS apps, you should already be familiar with it. To find your team identifier, log onto the iOS Member Center and click the name of your organization. You will find it there next to a label titled “Company/Organization ID”. I’ll show you another way to find it later on as well.
- organizationName – the name of the issuing entity.
- description – a short description of the pass.
This is a lot of information, so let’s see how is it useful to Apple.
Since the passes are not necessarily connected to an iOS app, there’s no automatic way for Apple to connect a pass to a given iOS developer account (which it needs to do to validate the pass contents). Passes might arrive to the user’s device independent from an app, via mail or web download (or another way). This is why the teamIdentifier is included in the meta information inside the pass – to connect the pass instance to an iOS developer.
Once Apple knows the identity of the developer who created the pass, they take the passTypeIdentifier to figure out which type of pass it is (of all the ones defined by a given developer account). Every pass type has its own certificate, so Apple can use this certificate and validate the signature included in the pass bundle – i.e., make sure nobody tampered with the pass contents.
Finally, the serial number is used to identify the unique instance issued for the given pass type.
To recap, consider an example:
- Joe’s Café has an iOS developer account with Apple. Thus, they use their team identifier on all their passes.
- They have store cards with preloaded store credit, which users can use to order yummy coffees in the shop. Store cards have passTypeIdentifier “pass.com.joescafe.storeCard”.
- They also have discount coupons that have a different passTypeIdentifier – “pass.com.joescafe.discountCoupon”.
- A given user can own more than one store card (for example, they bought one and a friend gave them one as a present), so the serial number is used to distinguish between two store cards of the same pass type (for example, “0134” and “0274”).
- Passes from the same passTypeIdentifier will be grouped together inside Passbook. When the user is at Joe’s Café, they’ll tap the stack of Joe’s Café store cards in Passbook, and choose the one they want to use – probably the one that still has credit on it!
By now you should understand pretty well how pass identification works. So “pass” this section and move on to the next, where you’ll create your first pass type.
Time to make it beautiful, baby!
They say an image is worth a thousand words – lucky for you, there’s no space for thousand words on the front side of the pass, so when in need you might as well use an image.
Go ahead and download the assets I’ve prepared for you:
PassAssets.zip. Extract the files and inside the FreeHugCoupon folder you will find a bunch of PNG files. Copy them over into your pass work folder.
And that’s it – you’re done! Phew, that was easy.
Wait, what? You don’t have to add any code inside pass.json to tell Passbook which image files to load. That’s right!
Passbook will automatically load image files following standard naming conventions. This means images named icon.png; icon@2x.png; logo.png; logo@2x.png; strip.png and strip@2x.png will be displayed on the pass, if provided. No need to do anything but include these files in the pass bundle. (There’s also few more images that this chapter will cover later on.)
Note: There’s one nasty gotcha about the pass images, which took me a while to figure out – the image files need to be exported as PNG24 format. For some reason the much smaller-in-size PNG8 format just won’t show up in Passbook.
“Let’s give that pass a try! I want to see it already!”, for sure you are crying in despair.
Unfortunately, until the pass bundle is complete, signed and zipped you cannot preview the pass. Passbook won’t display any invalid (incomplete) passes. So muster a little more patience and keep going.
The pass manifest
The pass manifest is another JSON file you need to create, and it describes all the files included in the pass bundle and their SHA1 checksums.
You can make this yourself by generating the SHA1 checksums for each file yourself (as I’ll show you in a minute), but so that you can move faster with building your first pass I’ve included an already-generated manifest.json file in the PassAssets.zip file you already downloaded and extracted. Find manifest.json inside the folder where you extracted the zip file and copy it over to your pass work folder.
It’s contents are as follows:
{
"strip.png":"25b4c9ff2bafe056f3e28379db0ef3fb460c718b",
"strip@2x.png":"dee775ed6fb3c7278b84c65853401e760caabc92",
"icon.png":"8eaa0896db93f2165fa417df3d002ce9c61fcd92",
"icon@2x.png":"555ce7f70f2f44fb7ac9d9f46df5738ec6250f37",
"logo.png":"e8c4edfbcae41d9d88fad7137d8ed30ae5f73e67",
"logo@2x.png":"1f9b1cc4c75b380ade07e9f2b7f37f988d9d14c3",
"pass.json":"<INSERT YOUR PASS SHA1 HERE>"
}
|
The SHA1 checksums for the images are already pre-filled, but the final checksum – the one for your pass.json file – is not. You are going to generate its SHA1 yourself. It’s quite easy – open up Terminal and navigate to your pass folder.
Note: If you aren’t familiar with navigating directories in the Terminal, do this: move your pass files into a folder on your Desktop and call it “FreeHugCoupon”, then launch Terminal and enter this command:
cd ~/Desktop/FreeHugCoupon
|
There you go.
Enter this command at the Terminal prompt:
The output of the command should look something like this (the actual checksum will be different for you):
SHA1(pass.json)= c24766ef5aa92197eace640fcc4fb584a505a733
|
Select the alphanumeric checksum value and in your manifest.json file replace “” with the checksum string. Save the file and you’re done! (Make sure you leave the quotes alone.)
NB! It’s important that you do not edit pass.json anymore until told to do so. If you add even one character to pass.json, the SHA1 checksum will change and your manifest.json will become invalid, since the checksum given there will no longer match the checksum of the modified pass.json file.
This is the last source file you need for your pass. Awesome!
Can I have your signature, please?
Now comes the most interesting part of creating a pass.
Remember the certificate you got from Apple for your pass type? You’ve imported it to your Keychain and you haven’t touched it since. Now you’re going to export the certificate and the key in PEM format, so that you can use them with OpenSSL.
Open up Keychain Access, select Certificates from the left menu (under Categories) and find the certificate called “Pass Type ID: pass.com.yourdomain.couponfreehug”. Make sure you’ve selected the item itself and not the private key underneath:
Next right-click on the certificate and choose from the popup menu Export “Pass Type ID: pass.com.yourdomain.couponfreehug”… Save the exported file as “Certificates.p12” inside your working pass folder. You’ll be presented with a dialog to choose a password:
To make the process a bit easier, just click OK – the certificate will be exported with no password protection.
Note: At this point you might be prompted to enter the password for the login keychain. If you are, then simply providing your user password should suffice.
The Certificates.p12 file now contains both the pass certificate and your private key. OpenSSL needs those in separate files, so now you have to extract them from the .p12 file.
Switch back to Terminal – it’s time for OpenSSL magic!
After making sure the current directory is the correct one (to double check, enter “ls –al” and hit Enter – you should see the file listing of the folder, and it should contain your Certificates.p12 file), enter the following command:
openssl pkcs12 -in Certificates.p12 -clcerts -nokeys -out passcertificate.pem -passin pass:
|
That’ll export only the pass certificate in PEM format and save it as “passcertificate.pem” inside the same folder. (OpenSSL will spit out the message “MAC verified OK” if the operation is successful.)
Next, export the key as a separate file with this command:
openssl pkcs12 -in Certificates.p12 -nocerts -out passkey.pem -passin pass: -passout pass:12345
|
Note that this time, you need to provide a password in order to export the key file. In this case, just use “12345” – obviously for production environments it’s advisable to use a strong password (doh!) – so, nothing of the “password1” or “passw00t” sort, please.
To sign your pass bundle you will need one more certificate – the WWDR Intermediate certificate, which authorizes the issuer of your own certificate – Apple. Chances are you already have it installed in your Keychain. Open up Keychain Access, select the “Certificates” category and look for a certificate called “Apple Worldwide Developer Relations Certification Authority” (yes, this is a quite long name indeed):
If by any chance you don’t have this certificate already imported, then open up in your browser this web page:
http://www.apple.com/certificateauthority/. Here you can freely download the most important Apple certificates you might need. Scroll down, find the WWDR certificate, download the .cer file and import it in Keychain.
You’re ready to go on with exporting the certificate. Back in Keychain Access right click on the certificate name and choose the Export option in the popup menu:
In the “Save as…” dialogue find the File format drop box and choose Privacy Enhanced Mail (.pem) option:
In the text field at the top of the dialogue give the file the name “WWDR.pem”, select your working pass directory as destination, and hit the Save button to finish the export.
You’re ready to create the signature. Enter this command:
openssl smime -binary -sign -certfile WWDR.pem -signer passcertificate.pem -inkey passkey.pem -in manifest.json -out signature -outform DER -passin pass:12345
|
Read through the command line above once more – it’s quite easy to understand all the parameters. The signer parameter is your pass certificate’s file name; inkey is the key file used to sign manifest.json; in is the input file name; out is the output file name; outform is the output format (you need “DER” to create a detached signature); and finally, passin is the password for the key file.
Now you have your signature and the production of the pass is almost complete.
The last remaining step is to combine the various files for the pass into a .pkpass file. Enter this command in the Terminal:
zip -r freehugcoupon.pkpass manifest.json pass.json signature logo.png logo@2x.png icon.png icon@2x.png strip.png strip@2x.png
|
By using the shell command “zip” you create a ZIP file called freehugcoupon.pkpass and the archive will contain all the files in the list that follows.
Believe it or not… that’s it! High fives all around! You did it!
Show me or I don’t believe it!
Yes, you’ve finally reached the point where you possess a complete and valid pass that you can see on your iOS 6-powered device.
Create an email message to yourself (or to the email account you have set up on your iOS 6 device) and attach the .pkpass file you just created. Send it over, open the mail in Mail.app and voila! You should see the attachment turn into a pass, like so:
If you see the pass show up – congratulations! You’ve made it!
If not, don’t be disappointed – it’s a long and error-prone process, so you’ll have to go back to the very beginning and check that you performed all the necessary steps. Make sure your JSON files are valid and that you’ve exported your certificate and key correctly.
Tip: If you want to check the validity of your JSON files, use an online tool like
http://jsonlint.com/ to quickly proof your code.
Time to see the pass! Tap on it inside the email message and Passbook should pop up showing you some greatness!
You can create passes using following GUI
iPass.pk.
Happy iCoding.