Skip navigation

It took an entire day to get In-App purchases to work.  TOTALLY unnecessary.  Apple’s docs on the subject are worthless, so I figure it’s time for another Coding Help Blog Post ™.

Alright, so getting a store in place is a bit involved, but I’ll do my best:

Include the StoreKit framework in your project and apply the appropriate #import.  In your main view controller, you will want to begin querying the App Store for product information as soon as possible so you can store the returned information before it’s needed to avoid network traffic slowing your user down.  You will also need to set up transaction observation in order to receive payment information.  To do this add the following lines to your main view controller:

NSSet* productIDs = [NSSet setWithObject:@”com.yourcompany.yourapplication.####”];
SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers: productIDs];
[productsRequest setDelegate: self];
[productsRequest start];
[[SKPaymentQueue defaultQueue] addTransactionObserver: self];

This will ping the App Store for product information pertaining to the product IDs associated with the productIDs given in the set.  When the request receives a response, it will call your view controller’s -productsRequest:didReceiveResponse: method.  In this method, you will want to store the products array provided by the response object.  In this method, you should also check the invalidProductIdentifiers property of the response object to make sure that everything made it through and to respond otherwise.

You can use the information from the response array to populate your GUI and allow users to purchase.  Once the user has chosen a product to buy you will have to intercept their choice and send out for App Store information.  To do this, you create a payment object with the desired product ID and send that out to the App Store.  That will look something like this:

SKPayment* thePayment = [SKPayment paymentWithProduct: someProduct];
[[SKPaymentQueue defaultQueue] addPayment: thePayment];

This method will ping the server with a payment request or a test request if you are using the sandbox.  The request will return to your -paymentQueue:didUpdateTransaction: method.  In here you need to determine the state of the payment object that the update returned.  To do this, iterate over all of the transactions while switching on their transactionState property.  Upon SKPaymentTransactionStatePurchased, you will need to validate the receipt information, begin downloading, and close out the payment.

Most important of these is receipt validation.  To do this, create a string using the returned transaction’s receipt data and turn that into a string.  This string is actually a JSON object which can then be passed to your PHP server (or whatever) to be then forwarded to the App Store for receipt validation.  Your code will probably look something like this:

NSString* jsonObjectString = [YourClass encode: (uint8_t*)[[transaction transactionReceipt] bytes]  length: [[transaction transactionReceipt] length];

NSString* completeString = [NSString stringWithFormat: @”http://yourserverhere.com/yourValidationScript.php?receipt=%@”, jsonObjectString];

NSURL* urlForValidation = [NSURL urlWithString: completeString];

NSMutableURLRequest* validationRequest = [[NSMutableURLRequest alloc] initWithURL: urlForValidation];

[validationRequest setHTTPMethod: @”GET”];

NSData* responseData = [NSURLConnection sendRequest: validationRequest  returningResponse: nil  error: nil];

NSString* responseString = [[NSString alloc] initWithData: responseData encoding: NSUTF8StringEncoding];

int success = [responseString intValue];

You will have to add the following code to your project.  It’s recommended you put this code in as a category to NSString, but it can be place pretty much anywhere.  The following code can be found here: http://www.cocoadev.com/index.pl?BaseSixtyFour at the bottom.

+ (NSString*) encode:(const uint8_t*) input length:(NSInteger) length {
    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t* output = (uint8_t*)data.mutableBytes;

    for (NSInteger i = 0; i < length; i += 3) {
        NSInteger value = 0;
        for (NSInteger j = i; j < (i + 3); j++) {
            value <<= 8;

            if (j < length) {
                value |= (0xFF & input[j]);
            }
        }

        NSInteger index = (i / 3) * 4;
        output[index + 0] =                    table[(value >> 18) & 0x3F];
        output[index + 1] =                    table[(value >> 12) & 0x3F];
        output[index + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';
        output[index + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';
    }

    return [[[NSString alloc] initWithData:data
                                  encoding:NSASCIIStringEncoding] autorelease];
}

This will encode your JSON string to Base64, which can then be passed to your server and on to the App Store for validation.

The variable ‘success’ can be anything your server wants to return to indicate success, but the App Store returns a 0 on success.

Hope that helps.  It was certainly a pain in the ass for me and my co-workers.  Good luck!

Advertisements

7 Comments

    • Andy Watson
    • Posted August 19, 2009 at 03:40
    • Permalink

    Would you be willing to share your php code for forwarding this to the app store? I have been playing around with this for a couple of days and i can still only get back a status of 21002.

  1. Thank you thank you THANK YOU A THOUSAND TIMES FOR THIS! I had to tweeze a bit of the code (minor typos, but it’s OK – Xcode and the docs are your friend), but I can FINALLY get a response from the Apple test server with all the details of the purchase. Whew!

    Andy: The quick-and-dirty version in PHP:

    header(‘Content-Type: text/plain’);
    $receipt = json_encode(array(“receipt-data” => $_GET[“receipt”]));
    $url = “https://sandbox.itunes.apple.com/verifyReceipt”; // Use buy vs. sandbox in production.
    $response_json = doHttpPost($url, $receipt);
    $response = json_decode($response_json);
    var_dump($response); // Just to see what you get back.

  2. Note: doHttpPost is whatever HTTP POST mechanism you’re comfy with.

    More notes on Stack Overflow here:

    http://stackoverflow.com/questions/1298998/verify-receipt-for-in-app-purchase/

    Kyle, sputteringly huge thanks once again to you and your team for sharing this! Bravo.

    • Roucis Kyle
    • Posted August 25, 2009 at 11:24
    • Permalink

    @Andy
    Sorry, my machine was in transit back home, so I had no opportunity to respond. Unfortunately, I was not able to glean permissions to post any PHP or HTML code as that information is property of the company. However, it seems that Joe has you covered. Thanks for that Joe! Glad you found it useful and good luck!

    @Joe
    You’re welcome, you’re welcome…etc. I’m glad to see that it was useful to someone. I really like the “sputteringly” for an adverb :). Thank you for providing some PHP code for us to chew on. I was not able to post any of my own, so I’m glad someone was able to skirt that. Please let me know if you find a different or better way to do the receipt validation and good luck to all of you!

    • Paula
    • Posted June 1, 2011 at 22:04
    • Permalink

    Hi Kyle,
    i am working on subscription app. Apple documentation talk about sending “shared secret” in order to get the receipt.
    Where does it go? Do I have to use my server for communicating with Apple?

    • Roucis Kyle
    • Posted June 1, 2011 at 23:02
    • Permalink

    Yes, you should (ideally) have your own server that will be will talking with Apple as well to house transaction data. If you are looking for more iPhone coding examples, head over to my new website location at http://www.kyleroucis.com.

  3. Thanks for the article – I coded up the other part (the PHP receipt validation) and have hosted the code here: http://www.chrismaddern.com/validate-app-store-iap-receipt-codes-online-tool/

    If anyone wants it… feel free!


One Trackback/Pingback

  1. By Verify receipt for in App purchase on 21 Sep 2011 at 1:55 pm

    […] this particular area as they don’t really give you any sort of example, I did find one useful article which helped me out a bit but something is still […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: