Delivering your Pass via an app (Medium)
Passes can be delivered through a companion iOS app. The app will provide a UI, using Apple's PassKit framework, allowing the user to view a Pass and choose to add it to their Passbook.
Getting ready
To follow these steps, it is assumed that you have some experience of Objective-C and creating iOS apps.
The example project, created as follows, can be downloaded from the following location:
http://passkit.pro/example-app
This app does not use Automatic Reference Counting (ARC), if you are using the code in an ARC environment, remove any calls to releasing objects.
How to do it…
Open Xcode and create a new, single view project. The setup options used for the example project are shown in the following screenshot:
In the Target settings, under Build Phases, expand the Link Binaries With Libraries section, and click on the + button. Search for the PassKit framework and add it. After this, the list of linked libraries should look like this:
Add your previously created Pass to the project by dragging the file to the project navigator, in the example, this Pass is called
Pass-Example-Generic.pkpass
.In PKEViewController.h, replace the existing code with the following: #import <UIKit/UIKit.h> #import <PassKit/PassKit.h> @interface PKEViewController : UIViewController<PKAddPassesViewControllerDelegate> @property (nonatomic, retain) IBOutletUIButton *addPassButton; - (IBAction)addPassButtonPressed:(id)sender; @end
In PKEViewController.m replace the existing code with the following:
#import "PKEViewController.h" @interface PKEViewController () @property (nonatomic, retain) PKPass *genericPass; @end @implementation PKEViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // Create the PKPass from the bundled file // In a real App this may be retrive from the network. NSString *passFilePath = [[NSBundle mainBundle] pathForResource:@"Pass-Example-Generic" ofType:@"pkpass"]; NSData *passData = [[NSDataalloc] initWithContentsOfFile:passFilePath]; NSError *passError; _genericPass = [[PKPass alloc] initWithData:passData error:&passError]; [passData release]; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)dealloc { [_addPassButton release]; [_genericPass release]; [super dealloc]; } #pragma mark - IBAction Methods - (IBAction)addPassButtonPressed:(id)sender { if (![PKPassLibrary isPassLibraryAvailable]) { NSLog(@"Passbook not available on this device"); return; } PKAddPassesViewController *addPassViewController = [[PKAddPassesViewController alloc] initWithPass:self.genericPass]; addPassViewController.delegate = self; [self presentViewController:addPassViewController animated:YES completion:^{ NSLog(@"Add Pass view controller presented"); }]; [addPassViewController release]; } #pragma mark - PKAddPassesViewControllerDelegate Methods - (void)addPassesViewControllerDidFinish:(PKAddPassesViewController *)controller { // Check if the Pass is now in the Pass Library PKPassLibrary *passLibrary = [[PKPassLibrary alloc] init]; if ([passLibrary containsPass:self.genericPass]) { // If the Pass is now in the Library, we can't re-add it, only view it. [self.addPassButton setTitle:@"View Pass in Passbook" forState:UIControlStateNormal]; } [self dismissViewControllerAnimated:YES completion:^{ NSLog(@"Add Pass view controller dismissed"); }]; } @end
Open PKEViewController.xib, place a
UIButton
with the title Add Pass to Passbook on the view and connect it toIBOutlet
addPassButton and IBActionaddPassButtonPressed for the sent event Touch Up Inside:Run the project in the iPhone Simulator. Tapping on the Add Pass To Passbook button will launch the PassKit UI, which displays the Pass and would allow the user to add the Pass to the Passbook app. At this stage however, the Pass will not be successfully added to the Passbook app as we need to use the correct provisioning profile.
To build the app to an iPhone, we will need an appropriate provisioning profile. Therefore, you need to log in to the Apple Developer Center:
https://developer.apple.com/account/ios/profile/profileList.action
Under Provisioning, click on the New Profile button, and follow these steps:
Choose a name for the development profile.
Tick next to your certificate.
Select the App ID in which you enabled Passes and generated certificates for previously.
Choose the devices you will be using.
Click on Submit.
Once generated, download the provisioning profile and open it to load it into Xcode.
In Target settings, under Info, ensure that the Bundle Identifier matches the app ID that was previously created and chosen in the profile creation.
In Build Settings, under Code Signing Identity, ensure the profile created above is selected under Debug.
Build to the device, and test that the presented Pass is successfully added to Passbook.
How it works…
The example app uses the PassKit framework to present a framework supplied view controller to the user, listen for a delegate callback when the user finishes interacting with the view controller and changes the button's title if the Pass was successfully added to Passbook.
Using the following code, the PKPass
object is created from a NSData
object:
NSString *passFilePath = [[NSBundle mainBundle] pathForResource:@"Pass-Example-Generic" ofType:@"pkpass"]; NSData *passData = [[NSDataalloc] initWithContentsOfFile:passFilePath]; NSError *passError; _genericPass = [[PKPassalloc] initWithData:passData error:&passError]; [passData release];
For the sake of simplicity, in this example, the Pass is loaded from a file bundled with the app. It is much more likely in a real-world app that a Pass will be downloaded from a network resource.
PKPassLibrary
provides access to the Passes contained in Passbook. It also provides a class method called isPassLibraryAvailable
that will tell you if Passbook exists on that device, for example Passbook is not present on iPads. This method is used in the example app to decide whether to show the Pass view controller.
if (![PKPassLibrary isPassLibraryAvailable]) { NSLog(@"Passbook not available on this device"); return; }
There's more…
Further documentation of the PassKit framework can be found in the following location:
https://developer.apple.com/library/ios/#documentation/UserExperience/Reference/PassKit_Framework/