This page contains samples of code integration in Objective-C for iOS.

NOTE 1: On iOS, the version that is checked during validation is the one stored in the CFBundleVersion field of the Info.plist file. Never put the version in the CFBundleShortVersionString field.

NOTE 2: These examples only covers a small subset of the possible behaviors. Carefully check the signature of the receipt validation function to learn about the required arguments.

NOTE 3: These examples serve as a basis to show you how to integrate the code and call it. Remember that you have to be creative in the way you integration validation code.

Basic receipt validation

This kind of validation should be executed in the early stage of the application's lifetime. When the validation succeeds, nothing happens; if the validation fails a receipt refresh request will be created and started.

Use the following options for the code generation (replace with your own values):

You need to implement a request delegate in order to receive notifications of the receipt refresh request:

//
// MyClass.h
//
#import <UIKit/UIKit.h>
#import <StoreKit/StoreKit.h>

@interface MyClass : NSObject <SKRequestDelegate>

// ...

@end

Then, call the validation code by passing the request delegate instance. Note that the requestDidFinish: method is called even when the user has cancelled the request. So you have to trigger another receipt validation in this method or later to be sure that the user has confirmed his credentials.

//
// MyClass.m
//
#import "MyClass.h"
#import "receipt.h"

// ...

- (void)strategicPlace {
    <Your Code Prefix>_CheckReceipt(self);
}

- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {
    // There was an error during refresh request
}

- (void)requestDidFinish:(SKRequest *)request {
    // The refresh request has finished

    // While debugging, use the following code to check that the receipt has been correctly retrieved
    NSURL *url = [[NSBundle mainBundle] appStoreReceiptURL];
    NSLog(@"Found %d", [[NSFileManager defaultManager] fileExistsAtPath:[url path]]);    

    // Perform another receipt validation to be sure if the user presses cancel
    // To avoid an infinite loop, you may implement a counter
    // You may also use dispatch_after to postpone the retry
    dispatch_async(dispatch_get_main_queue(), ^{
        <Your Code Prefix>_CheckReceipt(self);
    });
}

Retrieving receipt properties

This kind of validation is useful when you want to access to some receipt properties like the original bundle version (i.e. the version that was originally purchased). Whether the validation succeeds or fails, the given block will be called.

Use the following options for the code generation (replace with your own values):

In a strategic place (in a class for example), call the validation function.

//
// MyClass.m
//
#import "MyClass.h"
#import "receipt.h"

// ...

- (void)strategicPlace {
    <Your Code Prefix>_CheckReceipt(^(NSDictionary *receipt_dict, BOOL validationResult) {
        NSLog(@"[%d]", validationResult);
        if (validationResult) {
            NSLog(@"-> %@", [receipt_dict objectForKey:<Your Code Prefix>_RECEIPT_BUNDLE_ID]);
            NSLog(@"-> %@", [receipt_dict objectForKey:<Your Code Prefix>_RECEIPT_BUNDLE_VERSION]);
            NSLog(@"-> %@", [receipt_dict objectForKey:<Your Code Prefix>_RECEIPT_ORIGINAL_APPLICATION_VERSION]);
        }
    });
}

Checking InApp purchases

This kind of validation is used when you need to access the InApp purchase stored in the receipt. When the validation succeeds, the InApp purchases will be checked; if the validation fails nothing will be done.

Use the following options for the code generation (replace with your own values):

The code validates the receipt and call-back the given block for each given product identifiers. If the product identifier is found in the receipt, the block will be called back with the purchase information. Otherwise, no information will be provided.

//
// MyClass.m
//
#import "MyClass.h"
#import "receipt.h"

// ...

- (void)strategicPlace {
    // An array of the product identifiers to query in the receipt
    NSArray *identifiers = [NSArray arrayWithObjects:@"RECEIGEN_CONSUMABLE", @"RECEIGEN_NON_CONSUMABLE", @"OTHER", nil];

    // The validation code that enumerates the InApp purchases
    <Your Code Prefix>_CheckInAppPurchases(identifiers, ^(NSString *identifier, BOOL isPresent, NSDictionary *purchaseInfo) {
        if (isPresent) {
            NSLog(@">>> %@ x %d", identifier, [[purchaseInfo objectForKey:<Your Code Prefix>INAPP_QUANTITY] intValue]);
        } else {
            NSLog(@">>> %@ missing", identifier);
        }
    });
}

Checking InApp purchases and access receipt properties

This kind of validation is used when you need to access the InApp purchase stored in the receipt, while also accessing to the receipt properties. When the validation succeeds, the InApp purchases will be checked; if the validation fails nothing will be done.

Use the following options for the code generation (replace with your own values):

The code validates the receipt and call-back the given block for each given product identifiers. If the product identifier is found in the receipt, the block will be called back with the purchase information. Otherwise, no information will be provided.

//
// MyClass.m
//
#import "MyClass.h"
#import "receipt.h"

// ...

- (void)strategicPlace {
    // An array of the product identifiers to query in the receipt
    NSArray *identifiers = [NSArray arrayWithObjects:@"RECEIGEN_CONSUMABLE", @"RECEIGEN_NON_CONSUMABLE", @"OTHER", nil];

    // The validation code that enumerates the InApp purchases
    <Your Code Prefix>_CheckInAppPurchasesAndReceipt(identifiers, ^(NSDictionary *receipt_dict, NSString *identifier, BOOL isPresent, NSDictionary *purchaseInfo) {
        NSLog(@"-> %@", [receipt_dict objectForKey:<Your Code Prefix>_RECEIPT_ORIGINAL_APPLICATION_VERSION]);
        if (isPresent) {
            NSLog(@">>> %@ x %d", identifier, [[purchaseInfo objectForKey:<Your Code Prefix>INAPP_QUANTITY] intValue]);
        } else {
            NSLog(@">>> %@ missing", identifier);
        }
    });
}