In-App Purchase Manager for iPhone and iPad

This this class manages the whole process of making or restoring an in-app purchase. It's been extensively tested and is in active use on multiple App-store apps. View Pricing
scroll down for more

In-app purchases are difficult to implement because they involve lots of asynchronous calls to the app store. It's also necessary to handle all the possible errors that can occur:

  • Connection timeout
  • Lack of internet connection
  • Purchase failed
  • Purchase cancelled
  • Etc...

Using this class, if an error is received, a customizable alert message is displayed notifying the user of the problem.

This component encapsulates the whole process providing providing simple useful methods to:

  • Buy a product given a product identifier
  • Restore previous purchases
  • Get a list of available in-app purchases
  • Find out if a product has already been purchased

The class automatically records which products have been purchased and saves the information in NSUserDefaults.

While the request is being made, the class automatically deactivates touch on the current view and displays a waiting message.

The result of the transaction is provided by registering a delegate with the in-app purchase manager class. The delegate allows the outcome of the transaction to be handled.

Notes:

  • This component isn't applicable for in-app purchase which needs to be downloaded. It's only applicable for in-app purchases which are already included in the app and which are unlocked by setting a flag.

  • This component is aimed at iOS 6. It hasn't been tested it with iOS 5. If you want to use it with iOS 5 please be aware that there might be issues - however I am happy to help you solve any issues you might find.

  • To use this component, you need to have some knowledge of how in-app purchases work. It simplifies the process but it's still necessary to setup the in-app purchases in iTunes connect.

  • The screen shots are from an app where this product is enabled. This product is just the controller class not the app!

Pricing

14 day 14-day money-back guarantee

$29.99

Application License

  • Perpetual license

  • 1 application

  • Can distribute binary products only

  • Commercial use

  • 6 months support

Need custom services for this product? Get a quote

Setup and usage

To use this code the first thing you need to do is setup the in-app purchases using iTunes connect. Once that's done, each product will have a unique identifier.

Initialization:

Lets say that you're setting up your store screen. The first thing you need to do is initialize the class using the product identifiers. In the init method of the store manager class:

NSArray * identifiers = [[NSArray alloc] initWithObjects:
                             @"co.name.Widget1",
                             @"co.name.Widget2", nil];

[[BInAppPurchaseController sharedController] initializeWithProductIdentifiers: identifiers]

// We set the current class as the delegate class so it can receive
// messages from the controller
[[BInAppPurchaseController sharedController] setDelegate:self];

Next we need to implement the protocol. In the interface of our store manager:

@interface StoreManager : UIView<BInAppPurchaseDelegate>

Then we add the delegate methods:

-(void) requestFinishedWithStatus: (bRequestStatus) status {
    switch (status) {
        case bRequestStatusProductPurchased:
            break;
        default:
            break;
    }
}

-(UIView *) getView {
    return self.view;
}

The getView method provides the in-app purchases controller with access to the current view. That allows it to add a waiting message and prevent user input while it's making a request. The following statuses are available to the delegate:

* bRequestStatusProductsLoaded - a product list has been successfully loaded
* bRequestStatusProductPurchased - a product has been successfully purchased / restored
* bRequestStatusConnectionError - the purchase failed because of a problem with the connection
* bRequestStatusTimeoutOccurred - the connection timed out
* bRequestStatusProductLoadFailed - the product list could not be loaded
* bRequestStatusProductRestoreFailed - the products could not be restored
* bRequestStatusProductPurchaseFailed - the product purchase failed
* bRequestStatusProductIdentifierNotFound - the product identifier doesn't exist

Once the class is initialized, we're ready to make a purchase.

Making a purchase:

Imagine we're making a purchase by pressing a button:

-(void) buttonPressed {
    [[BInAppPurchaseController sharedController] buyProductWithIdentifier:@"co.name.Widget1"];
}

The following code will start the in-app purchase. The current view will display a waiting message and touches will be deactivated. The user will be prompted to enter their details and if the purchase goes through, a success message will be relayed to the delegate and the product will be unlocked. Otherwise a failure message will be sent to the delegate.

Displaying available products:

The available products can be displayed using the following code:

[[BInAppPurchaseController sharedController] requestProducts];

Again, the class will contact the server and will return a list of products. Any error or success will be reported to the delegate.

In the delegate method, you could put the following code to print details of the available products:

-(void) requestFinishedWithStatus: (bRequestStatus) status {
    switch (status) {
        case bRequestStatusProductsLoaded:
            for (SKProduct * product in [BInAppPurchaseController sharedController].products) {
                NSLog(@"Product Name: %@, price: %@", product.localizedTitle, [product.price stringValue]);
            }
            break;
        default:
            break;
    }
}

Restoring purchases

To restore purchases you would use the following code:

[[BInAppPurchaseController sharedController] restorePreviousPurchases];

Singleton Class

The in-app purchase controller is a singleton class which means that it can be used throughout your app. The important thing is to ensure that before using the class, you make sure the delegate is set properly.

Conclusion

As you can see, this class vastly simplifies the process of implementing in-app purchases. It doesn't necessarily cover the whole API but I'd be open to extending it if there's a demand.