How to create a single In-App Purchase in iOS 7

App Store IconThis “simple everyday” feature has caused me many headaches on many occasions. Implementing a simple unlockable feature isn’t as straightforward as it perhaps could be – and I’ll make it as simple as possible (so I won’t forget next time I need to add it to an app).

In this example we’re going to have one single feature that is already setup in iTunes Connect. It’s a non-consumable feature, such as “The Full Version”. To keep all our methods together in one place we’ll create a new NSObject class called “Shop”. This is where we’ll do most of the coding. Later we’ll also add code to the AppDelegate class.

This is a LONG article – grab a coffee and don’t get overwhelmed. It’ll take several tries to get comfortable with this matter (it’s not just you).

UPDATE: I’m explaining how to build this project step by step in a 7 part screencast – check it out here: http://pinkstone.co.uk/creating-an-in-app-purchase-in-ios-7-and-xcode-5-1/

Let’s start with our new Shop class. It’ll have two properties – these can be private:

@property (nonatomic, strong) NSArray *currentProducts;
@property (nonatomic, strong) SKProduct *mainProduct;

One holds an array of product identifiers (reverse domain notation, matching those in iTunes Connect), the other holds our actual product. Here’s a custom initialiser for the first property – it creates an array with one item (so you can expand with more products later):

- (NSArray *)currentProducts {
    
    // list of current product identifiers
    if (!_currentProducts) {
        _currentProducts = @[@"com.yourapp.fullversion"];
    }
    return _currentProducts;
}

Our Shop class needs a public method that can be called from the class that’s initiating the purchase. Here it is:

- (BOOL)validateProductIdentifiers {
    
    // let's check if the products exist in the App Store
    SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:[NSSet setWithArray:self.currentProducts]];
    request.delegate = self;
    [request start];
    
    return YES;
}

It looks more complicated than it really is: we’re initiating an SKProductsRequest with our Product ID and call its start method. The App Store will come back to us in a moment by calling methods of the SKProductsRequestDelegate protocol.

When we’re ready to initiate the purchase, create a new Shop instance and call this method. Use a property to hold your Shop instance, otherwise the instance is likely de-alloced before a response is received.

The App Store will get back to us with the products title, description and price a bit later on. Note that for a response to be received, your device needs to be online. So before calling the above method, make sure you’ve checked for network connectivity – and if that’s not available, don’t call the method.

Which reminds me: let’s make our Shop.h file react to the response by adding said protocol:

This content is for members only.

Making the Purchase

Since we’re using an alert view here to react to the purchase, its delegate needs to react. In my example this happens in a different class – not the Shop class (hence the above alert views’ delegates are set to self.delegate rather than self). Therefore we need a second public method in our Shop class which our main class can call if the user decides to go ahead with the purchase. Here it is:

This content is for members only.

Note that the transactionidentifier string is only available in iOS 7 and later. iOS 6 and earlier can similarly save the full receipt object as data. The Apple Documentation has more on how to do this.

Saving receipts isn’t strictly necessary, but if you do then you can check a valid purchase with the App Store sometime later.





2 thoughts on “How to create a single In-App Purchase in iOS 7

  1. Hi there, thanks for the effort! But I am having a problem, using iOS 7.1 and added the last 3 things in the AppDelegate, but now my Shop class still asks for an Delegate method that is in the AppDelegate (- (void)paymentQueue:(SKPaymentQueue *)queue) ?

    1. Hi Kets,

      you can instantiate and call the Shop class from anywhere in your project. The class that’s calling it though needs to be the delegate of the Shop Class so that it can react to the Alert View. A custom initialiser for the Shop may look like this:

      - (Shop *)newShop {
          
          if (!_newShop) {
              _newShop = [[Shop alloc]init];
              _newShop.delegate = self;
          }
          return _newShop;
      }
      

      I’ve just uploaded a 7 part screencast on how to build this project step by step – hope it helps: http://pinkstone.co.uk/creating-an-in-app-purchase-in-ios-7-and-xcode-5-1/

Leave a Reply