Beginning Passbook in iOS 6: Part 2/2

Marin Todorov

This post is also available in: Chinese (Simplified), Russian

Learn Passbook in the iOS 6 SDK!

Note from Ray: This is the second iOS 6 tutorial in the iOS 6 Feast! This tutorial is an abbreviated version of one of the chapters from our new book iOS 6 By Tutorials. Marin Todorov wrote this chapter – the same guy who wrote most of the “bonus” chapters in iOS 5 by Tutorials. Enjoy!

This is a blog post by iOS Tutorial Team member Marin Todorov, a software developer with 12+ years of experience, an independent iOS developer and the creator of Touch Code Magazine.

If you followed part one of the series, you know so far how to put together a pass bundle, how to sign it, how to send over e-mail. I am sure that your fingers itch to dig deeper into creating passes – the hottest, newest technology from Apple.

Buckle up – we’re continuing exactly where we left off last time!

Additional pass information

The pass has two sides: on the front you can add text information for several predefined areas; on the back you can show as many fields as you want. Let’s first do some front-end maintenance. ☺

Open up pass.json and find the primaryFields array declaration. On the same level, inside the coupon dictionary, you are going to add more sections to show more fields.

As you will be adding another key to the coupon dictionary, you need to first add a comma, and then define the new key. Add that comma after the closing square bracket at the bottom of the file (have a look at the picture below for the exact location).

On the next line after the comma, paste in this JSON code:

    "secondaryFields" : [
      {
        "key" : "expires",
        "label" : "Valid for",
        "value" : "Lifetime"
      }
    ],
    "auxiliaryFields" : [
      {
        "key" : "date",
        "label" : "Promo starts on",
        "dateStyle" : "PKDateStyleMedium",      
        "timeStyle" : "PKDateStyleNone",
        "value" : "2013-01-11T00:00Z"
      }
    ]

Now in addition to the primaryFields dictionary, you have secondaryFields and auxiliaryFields – these are the extra fields on the front side of the pass. They are not as visually prominent as the primary fields, but are still important enough to be on the front.

The auxiliary fields section should be of particular interest to you – it has some new properties that you haven’t used before. This field, unlike the rest of the ones you have, is a date field. Passbook takes care to convert the date/time values to the local time of the user, and also to format and localize the final text.

Have a look at the date field properties:

  • value – it’s a W3C datetime formatted value (for boring documentation on it, check http://www.w3.org/TR/NOTE-datetime).
  • dateStyle – the style to format the date part; must be one of: PKDateStyleNone, PKDateStyleShort, PKDateStyleMedium, PKDateStyleLong or PKDateStyleFull.
  • timeStyle – the same as the date style field; use the same constant names to define the time style.

That’s done! It’s time for you to do another build and see how the pass looks this time! You’re having fun already, right?

The build steps to perform:

  1. Make sure the JSON code looks OK (if not, be sure to use http://jsonlint.com/ to check).
  2. In Terminal, navigate to your working folder and get the SHA1 checksum of pass.json by running:
    openssl sha1 pass.json
  3. Place the pass.json SHA1 checksum in the manifest.json file.
  4. Generate the detached signature for the pass by running:
    openssl smime -binary -sign -certfile WWDR.pem -signer passcertificate.pem -inkey passkey.pem -in manifest.json -out signature -outform DER -passin pass:12345
  5. And finally, zip up the files into a .pkpass package:
    zip -r freehugcoupon.pkpass manifest.json pass.json signature logo.png logo@2x.png icon.png icon@2x.png strip.png strip@2x.png
  6. Send the file via email to your iOS 6 powered device and have a look!

Mission accomplished! Your pass should look like the one in the picture below:

The front is now almost done, so do something for the back!

Open up pass.json and add a comma after the last closing square bracket (you should be proficient in adding the comma to the right spot by now). After the comma, add a fields dictionary for the back of the card:

    "backFields" : [
      {
        "key" : "extras",
        "label" : "Extras",
        "value" : "Your friends receive 50% off price"
      },
      {
        "key" : "phone",
        "label" : "For more info",
        "value" : "800-1234567890"
      },
      {
        "key" : "terms",
        "label" : "TERMS AND CONDITIONS",
        "value" : "Free hugs last 18 seconds and must be claimed on your birthday. Bring your pass or an id"
      }
    ]

Fortunately the back of the pass is scrollable, so you can add as much info as you need. (Yes, sometimes those Terms and Conditions sections get pretty lengthy, so scrolling is absolutely necessary.)

Now – it’s time to see what the fields you just added look like on the pass. Build again following the instructions from last time and send the pass via email in order to see it on your device. Tap on the “i” button and the back will flip into view – it should look like the picture below:

So far so good! Also check out the phone number – it’s automatically converted to a link, which you can tap on to be taken directly to the Phone app. You can include other interactive information on the back too – like addresses (which open up in Maps) and email addresses (which of course open up in Mail).

The Pass Preview application

You probably already feel that it would be great if the process of building and previewing passes could be a little bit easier and faster. I mean, come on, do we really have to email the pass to ourselves every time we want to preview it?

Well – good news! Since I know you are going to want try out many color combinations, pictures and texts before settling on the perfect pass, in this part of the chapter you’re going to build an iOS app that will allow you to preview your passes a lot faster inside the iPhone simulator on your Mac. Yay!

Note: OSX 10.8.2 has now support for pass previewing straight on your mac. If you double click on a .pkpass file you will see how the pass looks like. However the only way to check whether the pass is valid still is to open it up on your device or simulator and try to import it.

There’s one way to install passes in Passbook that I haven’t mentioned yet. Besides sending a pass file over email and downloading it straight from a web server, you can also use the new PassKit framework in iOS 6 to install a pass from within an iOS app.

PassKit is a very simple framework, as it contains only three classes. To build a simple pass preview application, you are going to use the PKAddPassesViewController. This class takes in a PKPass instance and displays it on the screen.

In real life, your app will most probably fetch a pass from your server, or get it via iCloud, but in this example you’re just going to use passes that are bundled with the app.

Let’s go!

From Xcode’s menu, select File/New/Project…, and then select iOS/Application/Single View Application and click Next. Name the project “PassesPreview” and make sure it’s an iPhone app. Also ensure that Use Storyboards and Use Automatic Reference Counting are checked. Save the project in a location of your choice.

In the Project Navigator, select the Xcode project (the top item in the project tree) and in the strip on the right make sure the “PassesPreview” target is selected. Next click on the Build Phases tab and open up the Link Binary With Libraries strip.

Click on the (+) button, and in the list of frameworks double-click on “PassKit.framework” to include it in your Xcode project (or simply select PassKit.framework and tap the (+) button).

Now select MainStoryboard.storyboard – the app interface pops up. You need a full screen table, so grab a table view from the Objects palette and drop it on the main view:

Next, hold the Ctrl key and drag to the view controller object on the bottom palette. A popup menu will appears. Click on “dataSource”, then repeat, and the second time choose “delegate”. The table is now connected properly to your view controller.

And now, finally some Objective-C goodness!

Open up ViewController.m and replace its contents with this:

#import "ViewController.h"
#import <PassKit/PassKit.h> //1
 
@interface ViewController () //2
<UITableViewDelegate, UITableViewDataSource,
    PKAddPassesViewControllerDelegate>
{
    NSMutableArray *_passes; //3
}
@end
 
@implementation ViewController
 
- (void)viewDidLoad
{
    [super viewDidLoad];
 
    //4
    if (![PKPassLibrary isPassLibraryAvailable]) {
        [[[UIAlertView alloc] initWithTitle:@"Error"
                               message:@"PassKit not available"
                                   delegate:nil
                          cancelButtonTitle:@"Pitty"
                          otherButtonTitles: nil] show];
        return;
    }
}
 
@end

The code is pretty basic and there are just four things to note:

  1. First you import the PassKit framework headers.
  2. In the class extension of the ViewController class, you make it conform to the data source and delegate protocols of UITableView, and finally to the PKAddPassesViewControllerDelegate protocol.
  3. You declare an array instance variable to hold the list of all the bundled pass files.
  4. Finally in viewDidLoad, if the result of [PKPassLibrary isPassLibraryAvailable] is NO then you show a message to let the user know they don’t have Passbook available. (The user in this case is you, but it was a nice opportunity to show you how to check for Passbook availability, so I snuck it in.)

The goal will be to check if there are passes bundled with the app and if so, to show a list of them. The app will also show nice previews of the passes when the user taps on a given pass file name.

Add the following at the end of viewDidLoad:

    // 1 initialize objects
    _passes = [[NSMutableArray alloc] init];
 
    //2 load the passes from the resource folder
    NSString* resourcePath =
    [[NSBundle mainBundle] resourcePath];
 
    NSArray* passFiles = [[NSFileManager defaultManager]
                          contentsOfDirectoryAtPath:resourcePath
                          error:nil];
 
    //3 loop over the resource files
    for (NSString* passFile in passFiles) {
        if ( [passFile hasSuffix:@".pkpass"] ) {
            [_passes addObject: passFile];
        }
    }

What this simple code does is:

  1. First initializes the _passes array.
  2. Gets the list of all app resource files into the passFiles array.
  3. Checks all file names in passFiles and adds the ones having extension .pkpass to the _passes array.

Pretty simple! Now you have the names of all passes bundled with your app. Next, let’s show them in the table!

Add these three methods to ViewController.m in order to get the table view running:

#pragma mark - Table View
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}
 
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _passes.count;
}
 
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell"];
    if (!cell) cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier:@"Cell"];
 
    NSString *object = _passes[indexPath.row];
    cell.textLabel.text = object;
    return cell;
}

More simple code – you’ve probably done this many times already. However, do note some of the new code changes: you can now get the count of elements in an array by accessing the count method (it’s not a property) with return _passes.count. Getting elements out of an array (or a dictionary) is now simpler, too:
NSString *object = _passes[indexPath.row];

Some of these changes, like the dot-notation for methods, were around before iOS 6, but they are still fairly new. Whereas other stuff like the new NSArray notation is brand-spanking new, as you can read about in Chapter 1, “What’s New in Objective-C.”

This should be enough – you can run the project and see no warnings or errors, and get an empty table view on screen.

OK, time to include some passes with the app. First download the passes I’ve prepared in advance for you: Passes.zip. Extract the files and copy all the .pkpass files from the Passes folder into your Xcode project by dragging the .pkpass files and dropping them on your Xcode project root.

Note: Make sure to check that those files are added to the PassesPreview target. By default, Xcode won’t include them, as they are not code files or other known iOS resources.

Note: When you are working and designing your own passes do NOT check the “Copy items into …” checkbox. It’s much simpler to just link the .pkpass files from your Pass folder into the Xcode project. When you do code changes or replace an image, then you just rebuild the pass and restart the Xcode project, and the changed pass pops up on the screen.

OK, now that you’ve got some passes in the app, hit run and you’ll see the list of passes:

Finally, you need to add the code to show the selected pass on the screen. Add it to ViewController.m:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{   //1
    NSString* passName = _passes[indexPath.row];
    [self openPassWithName:passName];
}
 
-(void)openPassWithName:(NSString*)name
{
    //2
    NSString* passFile = [[[NSBundle mainBundle] resourcePath]
                          stringByAppendingPathComponent: name];
 
    //3
    NSData *passData = [NSData dataWithContentsOfFile:passFile];
 
    //4
    NSError* error = nil;
    PKPass *newPass = [[PKPass alloc] initWithData:passData
                                             error:&error];
    //5
    if (error!=nil) {
        [[[UIAlertView alloc] initWithTitle:@"Passes error"	
                                    message:[error  
                                         localizedDescription]
                                   delegate:nil
                          cancelButtonTitle:@"Ooops"
                          otherButtonTitles: nil] show];
        return;
    }
 
    //6
    PKAddPassesViewController *addController =
      [[PKAddPassesViewController alloc] initWithPass:newPass];
 
    addController.delegate = self;
    [self presentViewController:addController
                       animated:YES
                     completion:nil];
}

All right – there’s a fair bit of code, but it’s easy to go over it:

  1. First, when a table row is tapped you call openPassWithName.
  2. Inside openPassWithName you recreate the full path to the .pkpass file.
  3. Then you read the contents of the .pkpass file into an NSData instance.
  4. Then you create a new PKPass object by calling its initializer initWithData:error:.
  5. You check the error variable for any load issues.
  6. In the end, you create a new PKAddPassesViewController instance – this is a special view controller, which takes in a PKPass object and displays it. Assign the delegate property to self and present the controller modally on the screen.

You need one more method – the one called when the user closes the pass dialogue. (You’re not going to do anything special here, but it’s good to know your options for when you develop something more complicated.)

Add this method required by the PKAddPassesViewController delegate protocol:

#pragma mark - Pass controller delegate
 
-(void)addPassesViewControllerDidFinish: (PKAddPassesViewController*) controller
{
    //pass added
    [self dismissViewControllerAnimated:YES completion:nil];
}

Now you can run the project again and tap on the row saying FreeHug.pkpass – so cool! You can preview the passes and also import them into the Passbook app in your iPhone Simulator.

This is exactly the same dialogue that popped up inside your Mail app when you opened a pass attachment. Note that if you have an identical pass in your Passbook already, the Add button at the top right corner will be disabled.

Success!

One last touch – add the following at the end of viewDidLoad:

    if ([_passes count]==1) {
        [self openPassWithName:[_passes objectAtIndex:0]];
    }

When you are working on refining a single pass, you can save yourself the extra tap!

So far, you know everything you need to know about how to build a coupon, and you know how to easily test and preview your passes. This is the perfect combination of skills to approach the next topic in this part of the chapter: getting acquainted with the different styles of passes.

Dissecting pass styles…

Next you are going to look in more detail at the different styles of passes. Here is a preview of how they all look when imported in Passbook – you can see each type has a small style touch applied to the card:

So, how to create different passes? Go back to the source of the FreeHug coupon you were working on previously and open up pass.json. In the top-level dictionary you’ve added a key called “coupon”– the value of this key is a dictionary with field definitions. All passes work the same way – the only thing you need to do is change the key name from coupon to the style you’d like to have!

Santa’s well deserved vacation trip

To make the examples in this part a bit more fun, Vicki Wenderlich planned Santa’s vacation trip and prepared all the passes he’s going to need throughout his well-deserved vacation. With his iPhone’s Passbook loaded with coupons, VIP cards, and plane tickets bought in advance, Santa can have some time off after the Christmas rush without carrying around extra papers in his sack of toys. The first example is of course Santa’s plane boarding card for his flight to Tahiti.
Here’s the content of pass.json from the BoardingPass.pkpass example included in this chapter’s resources:

{
  "formatVersion" : 1,
  "passTypeIdentifier" : "pass.com.iOS6-By-Tutorials",
  "serialNumber" : "AX6184HJDG",
  "teamIdentifier" : "ABC1230000",
  "barcode" : {
    "message" : "AXB739-StClaus-A280",
    "format" : "PKBarcodeFormatQR",
    "messageEncoding" : "iso-8859-1"
  },
  "organizationName" : "Reindeer Airways LLC",
  "description" : "Train Boarding Pass",
  "logoText" : "Reindeer Airways",
  "foregroundColor" : "rgb(255, 255, 255)",
  "backgroundColor" : "rgb(230, 72, 56)",
  "boardingPass" : {
    "headerFields" : [
      {
        "key" : "header",
        "value" : "1",
        "label" : "Seat"
      }
    ],
    "primaryFields" : [
      {
        "key" : "from",
        "value" : "NorthPole"
      },
      {
        "key" : "to",
        "value" : "Tahiti"
      }
    ],
    "secondaryFields" : [
      {
        "key" : "meal",
        "label" : "Meal",
        "value" : "Milk & Cookies"
      }
    ],
    "auxiliaryFields" : [
      {
        "key" : "departure",
        "label" : "Departure:",
        "dateStyle" : "PKDateStyleMedium",
        "timeStyle" : "PKDateStyleMedium",      
        "value" : "2012-12-27T10:35Z"
      }    
    ],
    "backFields" : [
      {
        "label" : "terms & conditions",
        "key" : "terms",
        "value" : "Ticket is non-refundable.  Please specify which type of cookie you want upon check-in: chocolate chip, peanut butter, or M&M sugar cookie."
      }
    ],
    "transitType" : "PKTransitTypeAir"
  }
}

As you can see, the structure of the file is almost the same as what you had before, with the difference that instead of coupon you have a boardingPass key. There’s one other thing of interest: inside the boardingPass dictionary there’s an extra field called “transitType”. This field is specific for the boarding pass and is what sets the little transit icon shown on the front side of the pass.

For transitType, depending on what kind of boarding pass are you building, you can use one of the predefined type constants: PKTransitTypeAir, PKTransitTypeTrain, PKTransitTypeBus, PKTransitTypeBoat, and PKTransitTypeGeneric.

And that’s the difference between building a coupon and a boarding pass! The source code above results in this nifty boarding pass:

Can you spot Santa’s meal preferences on the boarding card? So can the flight attendant – he’s up for a relaxing flight!

Boarding Pass style considerations

  • Note that the primary fields are using quite a large font so that they can’t show more than a few characters of text. Longer destination names like “San Francisco” are going to be cut off, so consider using destination codes instead of names. It would be best is to show the full name of the city as the field label, and the destination code as the value.
  • The boarding pass doesn’t show any pictures, so use only the icon and logo image files.
  • It’s a great idea to use the header field for things like airport departure gate, departure platform or a seat number.

Make sure you are using the correct transit type for your boarding pass! Here are the different icons shown, depending on type:

And here’s also a preview of the positions of all available fields you can use (of course you don’t need to use all of the fields; this is to give you an overview of the styling and the positions of the available fields):

When designing a new pass there’s one major point you have to always pay attention to: the different styles of barcodes take up different amount of space on the front side of the pass. The PDF417 barcode has a horizontal layout, so it kind of fits nicely at the bottom of the card – leaving more space for the pass fields (like in the example above). On the other hand the QR barcode has a square shape and takes up more space vertically. Observe the same pass from above when it features a QR barcode:

You can clearly see there’s less vertical space between the fields so that the barcode can also fit on the card; therefore: always start designing a pass with the correct type of barcode, so that you can have the correct field layout from the start!

Note: If you reuse any of the code from the example passes in this part of the chapter, don’t forget to change the team and pass type identifiers to your own – otherwise, your passes won’t import to Passbook.

Are you a premium member?

Next, let’s look into store cards. These are very popular and already widely-used, so I bet many merchants will want to use the iPhone pass format to digitalize their store cards.
There is a store card example included with this chapter. Santa is up for some active recreation so he bought a premium package from the Tahiti Surf & Snorkel school. His pass also conveniently shows him how many pre-paid lessons he has left on his account with the school.

As you can see, the layout of the store card is somewhat similar to the coupon, but the header styling is different. Have a quick look at the source code for the pass above:

{
  "formatVersion" : 1,
  "passTypeIdentifier" : "pass.com.iOS6-By-Tutorials",
  "serialNumber" : "00012",
  "teamIdentifier" : "ABC1230000",
  "barcode" : {
    "message" : "q2eq3aaa",
    "format" : "PKBarcodeFormatPDF417",
    "messageEncoding" : "iso-8859-1"
  },
  "organizationName" : "Tahiti Surf & Snorkel",
  "description" : "Diving Lessons",
  "logoText" : "Tahiti Surf & Snorkel",
  "foregroundColor" : "rgb(255, 255, 255)",
  "backgroundColor" : "rgb(68, 200, 190)",
  "storeCard" : {
    "headerFields" : [
      {
      "key" : "lessons",
      "label" : "Lessons",
      "value" : "4"
      }
    ],
    "primaryFields" : [
      {
        "key" : "balance",
        "label" : "Class",
        "value" : "Premium"
      }
    ],
    "secondaryFields" : [
      {
        "key" : "memberName",
        "label" : "Name",
        "value" : "Mr. Claus"
      }
    ],
    "backFields" : [
      {
        "key" : "date",
        "label" : "Valid from:",
        "dateStyle" : "PKDateStyleMedium",      
        "timeStyle" : "PKDateStyleNone",      
        "value" : "2013-01-01T00:00Z"
      },
      {
        "key" : "date",
        "label" : "Valid until:",
        "dateStyle" : "PKDateStyleMedium",      
        "timeStyle" : "PKDateStyleNone",      
        "value" : "2013-01-03T00:00Z"
      },
      {
        "key" : "terms",
        "label" : "TERMS AND CONDITIONS",
        "value" : "Lessons must be used between 1/1/2013 and 3/1/2013.  Appointments for lessons must be made no less than 48 hours in advance.  Customer must be able to swim."
      }
    ]
  }
}

The basics, which you already well know and love, are all there, so I’m not going to cover them again. However, there are a few things to discuss inside the backFields dictionary. You have two date fields and a text field for the terms and conditions, and all three fields contain dates. This is a great opportunity to connect the pass with the Calendar on the iPhone! Tap the “i” button at the bottom-right corner and have a look:

Passbook auto-detects the dates and turns them into links. When they are tapped, the user is presented with an action sheet, which can take them to the specific day in the Calendar, or help them create an event in the Calendar for the specific day or period. Outstanding!

Store card style considerations

Usually a store card holds the customer’s credit with the store. It’s a good idea to put that information in the primary area of the pass. Passbook can render different currency styles as well, so if you are showing money amounts, consider showing them in the user’s currency, like so:

Passbook even automatically removed the digits after the floating point for the amount in Japanese Yen, because the Yen doesn’t use a decimal point! (1 is the lowest possible value.)

To style a field as a currency amount, you need a numeric value (so, no quotes around the number) and there has to be an extra key to define which currency to use. For an amount in Japanese Yen, that would result in the following code:

{
  "key" : "amount",
  "label" : "Current credit store",
  "value" : 45.20,
  "currencyCode" : "JPY"
}

And finally, here are the kinds of fields a store card can show on its front:

It’s a ticket, it’s a pass… it’s an iPhone!

The next pass type on the list is the event ticket – it can be a concert ticket, cinema ticket or any other kind of ticket you can come up with!

Switch back to the PassPreview app and select ConcertTicket.pkpass. A stylish ticket card pops up:

As you can see, Santa is not going to bed early – instead he plans to enjoy a hula show and a nice evening on the beach. It’s easy when you plan ahead and have all the tickets in your pocket – conveniently stored on your iPhone!

The event ticket pass has a couple of unique features. If you provide a background image file, it gets stretched, blurred, and is set as the background of the whole card. If you provide a thumbnail image (thumbnail.png and thumbnail@2x.png), the image shows up on the right-hand side.

Note that since the background image is rendered over the whole front side of the pass, you don’t need to specify “backgroundColor” in your pass.json file.
Besides those specifics, the rest you already know well:

{
  "formatVersion" : 1,
  "passTypeIdentifier" : "pass.com.iOS6-By-Tutorials",
  "serialNumber" : "000024567",
  "teamIdentifier" : "ABC1230000",
  "barcode" : {
    "message" : "12946390566",
    "format" : "PKBarcodeFormatQR",
    "messageEncoding" : "iso-8859-1"
  },
  "organizationName" : "Tahiti Beach Hula Show",
  "description" : "Entrance ticket to Tahiti Beach Hula Show",
  "logoText" : "Tahiti Beach Hula Show",
  "foregroundColor" : "rgb(255, 255, 255)",
  "backgroundColor" : "rgb(242, 121, 55)",
  "eventTicket" : {
    "primaryFields" : [
      {
        "key" : "name",
        "value" : "Tahiti Beach Hula"
      }
    ],
    "secondaryFields" : [
      {
        "key" : "location",
        "label" : "Location",
        "value" : "Next to Maxi's Martini Bar"
      }
    ],
    "auxiliaryFields" : [
      {
        "key" : "date",
        "label" : "Event date",
        "dateStyle" : "PKDateStyleMedium",
        "timeStyle" : "PKDateStyleMedium",      
        "value" : "2012-12-29T19:00Z"
      }    
    ],
    "backFields" : [
      {
        "key" : "terms",
        "label" : "Terms & conditions",
        "value" : "This ticket may cause happiness and good cheer!  Free lei with ticket."
      }
    ]
  }
}

After seeing a few different pass.json files, it becomes pretty easy to understand the pass source code! Again, you can include many kinds of information on the front and back of the pass in the manner already covered.

Event Ticket styling considerations

  • If you provide a background image, but no thumbnail image, then Passbook will also show the background image in the thumbnail spot on the right-hand side.
  • You cannot disable the blur effect on the background – that’s how Apple makes sure the text information stands out.
  • For event tickets like conferences, the thumbnail image is a great way to include the attendee’s photo straight on the front of the pass.

Finally, here’s also a preview of all the possible fields you can use on the front of an event ticket:

It’s the pass you always wanted to have!

Finally, we get to the pass you always wanted to have! Or to create. Or to create and then have!

The last type of pass is the generic pass. It has basic styling, can feature many different text fields, can display a picture on the front side, and you can use it for all kinds of passes that don’t fit well in the other four categories – coupon, boarding pass, store card, or event ticket.

And now we discover Santa’s drink of choice: after all the hard work delivering billions of presents around the world in a night, he’s up for a cold martini on the beach. Enjoy responsibly, Santa!

Open up PassPreview and tap on GenericPass.pkpass:

As you can see, this card doesn’t fit neatly into any of the other four pass styles. It gives the bearer access to the VIP lounge of Maxi’s Martini Bar and a free martini each day. It’s more like a club membership, for which there exists no pre-defined style.

But this “generic” pass actually looks pretty good! Why yes – you still have all the possible ways to customize it that were already discussed! There’s nothing special inside pass.json, except of course for the pass type key being generic:

{
  "formatVersion" : 1,
  "passTypeIdentifier" : "pass.com.iOS6-By-Tutorials",
  "serialNumber" : "123456",
  "teamIdentifier" : "ABC1230000",
  "barcode" : {
    "message" : "7465-454-2234-1",
    "format" : "PKBarcodeFormatPDF417",
    "messageEncoding" : "iso-8859-1"
  },
  "organizationName" : "Maxi's Martini Bar",
  "description" : "Generic Pass Example",
  "logoText" : "Maxi's Martini Bar",
  "foregroundColor" : "rgb(33, 33, 33)",
  "backgroundColor" : "rgb(122, 230, 88)",
  "generic" : {
      "headerFields" : [
        {
          "key" : "header",
          "value" : "VIP"
        }
      ],
    "primaryFields" : [
      {
        "key" : "member",
        "value" : "Santa Claus"
      }
    ],
    "secondaryFields" : [
      {
        "key" : "faux1",
        "value" : ""
      },
      {
        "key" : "secondary1",
        "label" : "Rewards Earned",
        "value" : "Free Specialty Martini",
        "textAlignment" : "PKTextAlignmentRight"
      }
    ],
    "auxiliaryFields" : [
      {
        "key" : "faux2",
        "value" : ""
      },
      {
        "key" : "status",
        "value" : "Level 3",
        "label" : "Membership Status",
        "textAlignment" : "PKTextAlignmentRight"
      }
    ],
    "backFields" : [
      {
        "label" : "terms & conditions",
        "key" : "terms",
        "value" : "Must show proof of ID to claim rewards."
      }
    ]
  }
}

Wait… what? (If you didn’t notice anything strange, maybe you need to look over the code once more?)

What is this field supposed to do?

      {
         "key" : "faux1",
         "value" : ""
      },

Yes – it’s time for some trickstery! The position of the fields on the front of the pass are predefined, and so… it goes like this: the first secondary field shows up on the left-hand side, the second secondary field shows up on the right-hand side, the first auxiliary field shows up… etc., etc.

So what if you want to show a piece of text where normally the second secondary field would be, but you don’t need to show anything in the first secondary field?

Aha! Define a faux first secondary field with an empty value and no label (like in the code example above). Neat!

Another thing to note is the “textAlignment” key used in the code above. Using this key, you can tell Passbook which way to align the text in a given field. You can choose between the following list of predefined alignment constants: PKTextAlignmentLeft, PKTextAlignmentCenter, PKTextAlignmentRight, PKTextAlignmentJustified, and PKTextAlignmentNatural.

Here’s an overview of all the possible fields you can use on the front of the generic type of pass:

OK! You’ve made it this far and I hope the trip was rewarding! You know everything you need about designing, coding and previewing passes. You’ve learned a whole lot!

Where to go from now?

You covered a lot of the basics of pass creation. You know how to put together a pass, what types of passes there can be, how to manage the pass assets, and much more!

There’s lot more you can learn about pass services if you dig into iOS 6 by Tutorials. What you will learn in the chapters covering Passbook is:

  • Automated pass distribution via email or web
  • Location and time aware passes
  • Updating passes
  • Sending notifications to pass owners
  • And tons more…

I hope you enjoyed this tutorial and it’s a rich and useful resource for you. If you have any questions or comments, please join the forum discussion below!

This is a blog post by iOS Tutorial Team member Marin Todorov, a software developer with 12+ years of experience, an independant iOS developer and the creator of Touch Code Magazine. You can also find me on

Marin Todorov

Marin Todorov is an independent iOS consultant and publisher with complimentary background in server and desktop development.

He started developing on an Apple ][ more than 20 years ago and keeps rocking till today. Meanwhile he has worked in great companies like Monster Technologies and Native Instruments, has lived in 4 different countries, and (more recently) is one the founding memebers of the raywenderlich.com tutorial team.

Besides crafting code, Marin also enjoys bloging, writing books, teaching and training others, and speaking at mobile conferences. He sometimes open sources his code. He walked the way to Santiago.

User Comments

17 Comments

[ 1 , 2 ]
  • If your pass was not added its because something is wrong with the pass.

    Look for the passbook debugging section link in the tutorial online.

    You'll be looking at the server log files to see what the problem is.
    marciokoko
  • Thank you for tutorial.

    In class/EggHuntPass.php file I added this:
    Code: Select all
    function __construct() {
          $db = Database::get();
          $nome = $db->prepare("SELECT codiceTemplate FROM esercenti WHERE IDEsercente = ".$_POST['codEsercente']);
          $nome->execute();
          $row = $nome->fetch(PDO::FETCH_ASSOC);
          $template=$row['codiceTemplate'];
       
          $this->keyPath = realpath(dirname(__FILE__)."/../".$this->keyPath);
          $this->sourcePath = realpath(dirname(__FILE__)."/../".$this->sourcePath)."/".$template;
          parent::__construct($this->sourcePath);
       }

    I put the images and pass.json files in N different folder called 0/1/2/... Each with a different format...

    And everything work!

    But when I update pass from DB, it doesn't change on my iPhone. Do you know why?
    It say "Couldn't update pass".
    Maybe because it re-call EggHuntPass.php without the folder 0/1/2...?
    swim89
[ 1 , 2 ]

Other Items of Interest

Ray's Monthly Newsletter

Sign up to receive a monthly newsletter with my favorite dev links, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

Hang Out With Us!

Every month, we have a free live Tech Talk - come hang out with us!


Coming up in September: iOS 8 App Extensions!

Sign Up - September

RWDevCon Conference?

We are considering having an official raywenderlich.com conference called RWDevCon in DC in early 2015.

The conference would be focused on high quality Swift/iOS 8 technical content, and connecting as a community.

Would this be something you'd be interested in?

    Loading ... Loading ...

Our Books

Our Team

Tutorial Team

... 49 total!

Update Team

Editorial Team

... 23 total!

Code Team

  • Orta Therox

... 3 total!

Translation Team

  • Heejun Han

... 33 total!

Subject Matter Experts

  • Richard Casey

... 4 total!