Kotan Code 枯淡コード

In search of simple, elegant code

Menu Close

Getting App Store Receipts in your Mac OS X Lion App

As I was trying to write code that utilized StoreKit to allow users of my sample application to make purchases, I ran into a particularly sticky problem: I couldn’t get receipts for my application.

The first time you sift through the Apple documentation, it makes it seem as though if you check for a receipt in your bundle and do not find one, then you simply exit the application with code 173 and a receipt will magically appear within that bundle. While technically correct, as with many Apple documents, it doesn’t give you the whole story in the same place.

The issue here is that you cannot obtain receipts while running underneath Xcode. Further, receipts are only possible while running as an App that was installed via an App Store package. So here’s the rub – how the heck do you get a receipt in your application (which is required before your application can support In-App Purchases) if you can’t do so from inside Xcode?

First, you need to write the code that does an exit(173) if there is no receipt in your App Bundle (if you read my previous post, then you’ll know that you should also be validating the contents of the receipt, not just its presence). You can do so with code like this:

    NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
    if (![[NSFileManager defaultManager] fileExistsAtPath:[receiptURL path]])
    {
        NSLog(@"no receipt - exit the app with code 173");
        exit(173);
    }

The purpose of the exit(173) is to tell the OS that there was a problem with receipt validation. If you have signed your application with a Developer certificate (and your app is running outside of Xcode as an App Store-installed App!), then the OS will obtain a development receipt for the application and place it in the bundle for you automatically.

To test your code, you need to build an installer package for the application. To do that in Xcode 4.2, click the “Product” menu then choose “Build for Archiving”. Then choose “Product” and then “Archive”. This will create a new archive for your application. Note that your application must be signed with a developer certificate and your provisioning profile needs to be valid as well.
From the Xcode Organizer window, select the archive you just created and click “Share…”. When prompted, choose the “Mac OS X App Store” package type and save the package to some location that has a relatively short and simple path (like your desktop).

You cannot double-click this .pkg file!!! (Did I mention you can’t double-click this file?!)

Secondly, before you do anything, CLEAN YOUR BUILD. Using Xcode, select “Product” and then “Clean”. If you run the command line I’m about to show you while you still have a compiled bundle on disk, your application will not install into /Applications but will get all messed up and be installed in some obscure location you can’t find.

Now that you have created the package and cleaned your product (There is no .app file for your app on disk!), you can run the following command from a Terminal prompt:

sudo installer -store -pkg (path to package including filename) -target /

This will install the application in the /Applications directory and you should even see the application appear as an icon in your Launchpad list. Now when you launch your application it will obtain a receipt. With a receipt in the bundle, all of the StoreKit code for completing financial transactions will work.

Great, right? Well, not really. The sucky part of this is that the StoreKit code for completing purchases will not work when debugging in Xcode because when you’re debugging in Xcode your application does not have a receipt. This means you’re going to have to litter your code with #ifdefs to keep it from attempting to discover and validate the receipt when in debug/Xcode and you’ll have to avoid attempting to complete an In-App Purchase when you’re debugging in Xcode. Also, don’t forget that you need to create test users in iTunes Connect in order to complete purchases for sandbox In-App Purchases.

It’s not the end of the world but I think it could definitely be smoother. Ideally, I should be able to simulate purchases while Xcode is running in some fashion so that I don’t have to stop my debugging session, build an archive, do a clean, install my app, and then launch the app just so I can watch In-App Purchases go through.

Anyway, I hope these instructions help someone who is struggling with App Store receipts on Mac OS X like I was this weekend.