Creating an In-App Purchase in iOS 7 and Xcode 5.1

In this 7-part screencast series I’ll show you how to create an In-App Purchase in iOS 7 with Xcode 5.1.

The course will run you through everything from setting up your product in iTunes Connect, creating a custom shop class for easy re-use, making “first contact” with the App Store and how to deal with its responses. I’ll explain the overall concept in Part 1.

Parts 1+2 are free to watch. The rest is for members only.

Part 2 describes how to setup your your app for use with In-App purchases. We’ll setup a new App ID in Member Center, and create a product in iTunes Connect.

This content is for members only.

I’m following my earlier two articles almost to the letter, here they are for reference:

35 thoughts on “Creating an In-App Purchase in iOS 7 and Xcode 5.1

  1. Hey there! This tutorial is VERY helpful, not like the other ones that I have found online. I have spent 2 full days trying to make this work, and well, i’m still in the same situation. I like the tutorial, but i have more than one IAP for customers, i’ve tried lots and lots of things trying to change the code from this tutorial but i just can’t seem to get it to work. the furthest i got to was i got for two buttons to display each a different IAP, BUT, when it was purchased and downloaded it would only download the first IAP even though It displayed the information from the second one. I really need help and been working four hours, please and thanks.

    P.S i have a total of 6 IAP i want to include.

    1. Hi Miguel, thanks for signing up – glad you’re enjoying the tutorials!

      Multiple IAPs are more complex, and there are several ways of implementing this feature. In truth it depends on your coding skills which way you choose. In a nutshell, you can hard-code them (as we did here, which is simpler), or you can pull in all products from the app store and display them dynamically. This would require a sophisticated dynamic table view and is more involved from a UI point of view.

      The simplest and easiest way is to amend the above demo project and duplicate the Shop class so you have a different class for each product (instead of Shop, you can call it Product1, Product2, etc). This probably involves the least amount of code changes: all you have to do is update the product identifier and make sure you call the correct Shop class from the view controller. The only other change that’s required is in the StoreKit observer method that loops through your completed transactions: before unlocking your product, test for the correct product identifier (transaction.payment.productIdentifier). Something like this:

      if ([transaction.payment.productIdentifier isEqualToString:@"com.domain.product1"]) {
          // unlock product 1
      if ([transaction.payment.productIdentifier isEqualToString:@"com.domain.product2"]) {
          // unlock product 2

      I’ll see if I can demonstrate this in another video. Watch out for new posts 😉

      Does this make sense in principle? That’s how I would do it.

  2. Hi Jay,
    I have problems with your tutorial. The single product always return “null”. I cannot show the price or something else. I followed your instructions carefully.

    Any idea?


    1. Hi sebspi,

      this is tough to diagnose without seeing your code. I would probably set breakpoints in the Shop class, at the end of makeThePurchase. You should see if self.thisProduct is nil or if it contains a value. If it does, then your view controller may not hold a reference to the shop class. If it does not, then try a breakpoint at the end of makeThePurchase and see if self.allProducts is a valid array of products, and so forth. Track the null value back up the chain until you find where it should exist.

      Good luck!

  3. Hi Jay I’m looking for a consumable IAP tutorial.. Wondering I should subscribe to this non consumable tutorial.. Great videos btw…

    1. Hi torresho, I must admit that I’ve never tried a consumable IAP myself, but in a nutshell it’s the same principle as a one-off IAP. In addition your app needs to keep track of quantity.

      I’m saving a BOOL in user defaults for that, but instead you could easily save an NSNumber value which you can check against (if it’s 0, prompt the user to buy more goodies).

  4. Hi, how could I let my view controller (that is not a root view controller) from appdelegate know what the app store communicated back?

    I want appdelegate to call my view controller and tell it to update in a proper way.

  5. Brilliant tutorial. Apple have made is so difficult to add In-App purchases it surprises me how many apps have it! Your explanation made perfect sense and I can honestly say that I now fully understand how In-App purchases work and have it working in an app I am developing thanks to you! 😉

  6. Hey Jay, I have everything working but I have just noticed that if the user taps the ‘Restore’ button but decides not to continue (let’s say tapping the cancel button in the alertView that iOS provides to input user password) then there’s no way of telling if the user has done so, unlike if the user taps the cancel button when making the In-App purchase for the 1st time which does tell you if the user cancels.

    Any idea how to find out if the user has cancelled half way through the restore process?

    1. Hi Chrjy,

      very good point indeed! The SKPaymentTransactionObserver protocol has two methods that you can implement: one will be called when the restore was successful, and the other one if there was a problem. Add them to your AppDelegate.m file (or more accurately, the class that is the SKPaymentTransactionObserver):

      - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
          // called when restored transactions have finished successfully
          // not required
      - (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
          // called when restored transaction have finished with an error
          // for example, user gives the wrong password or hits cancel
          // not required

      I’ve added them in the demo project just underneath the updatedTransactions method. Implementing these is optional, but it is a nice touch to let the user know if things went well or not. Thanks for bringing it up!

      1. Thanks Jay, I’ve just added this and it works perfectly. Your website is now firmly bookmarked and I will be referring to it often!

  7. Hey Jay! Great Work. I have a question. I’m going to add one In-App Purchase.
    Full version:

    Unlock PDF report
    Unlock BackUp

    And month later I want to update my app and change this in-app purchase.
    Full version:

    Unlock PDF report
    Unlock BackUp
    Remove Ads
    Remove entry count limitation
    Remove photo count limitation

    Can I add some restrictions to In-App purchase? Or Apple will reject my app?

    1. Good question – I guess it depends on if after the first in-app purchase some functionality would be made available, and then removed when you introduce your next update. For example, if the Unlock PDF option would also remove the adverts. In that case, the customer would have paid for it and would expect the app to stay that way. If you bring those back with an update and charge for removing adverts in addition, I guess then Apple would reject your app (or at least your customers would get upset).

      On the other hand, if you simply introduce another in-app feature later, I don’t think Apple should have a problem with it.

      1. Thank you! I didn’t make all clear. My Fault.
        I’m going to submit my new free app without Ads and with in-app purchase:
        Full version:

        Unlock PDF report
        Unlock BackUp

        But later I’m going to update that app and add Ads, entry count limitation and photo count limitation in it. In that case I should update In-App purchase:
        Full version:

        Unlock PDF report
        Unlock BackUp
        Remove Ads
        Remove entry count limitation
        Remove photo count limitation

        After update:
        Users who already have full version will not see Ads or have another restrictions.
        Users who use not full version will see Ads( after update app ), have entry count limitation and photo count limitation.

        And I worry that Apple will reject my update. I have to decide about In-App purchase for first version of my app. Should I add all restrictions for first version, or I can add it later with update. I would prefer to add restrictions with update.


        1. I guess only Apple can answer that 😉 In theory your plan sounds good and there’s no reason why they should reject your app, but Apple follow their own ideas of what’s acceptable and what is not.

          Just a thought: it’s a LOT of effort to add all these different in-app products, for you as much as for the user who will buy your app. As a user, I’m happy to make an in-app purchase to unlock “pro” functionality – but I would feel rather annoyed if I have to go through this several times to get all available features. Especially if I’ve just done it, and then an update comes along that asks me to make more such purchases. Just my two cents.

  8. Hi Jay, great article – following it through has allowed me to add in-app purchase to my own app – thank you!

    I’ve a question though, in iOS9 UIAlertView is deprecated, and UIAlertController is advised to be used instead. However, this can only be called from a view controller – but you have it running in a separate “shop” class. Can you advise the best way for the code to be updated to deal with this?

    Also the shop class includes a method called “cantbuyanything” if the user has disabled in-app purchases in settings. I’ve included an alert in there to let the user know, however I’ve found that the method is never called – instead iOS displays it’s own message to let the user know it’s disabled. Can you advise what should be amended so that the method is run?

    If you can help with these I’d be really grateful! Thanks in advance.

    1. Hi AHAH, glad the article helped you. I think the system ate my previous response, perhaps it’ll remember it this time :-)

      You can (and should) indeed replace the alert view with an action controller. They’re easy to setup, I’ve explained how to do it here:

      As you say, the new alert view class uses blocks to handle events instead of a delegate. To have another class react to the outcome of an alert view, send a notification in the completion block and have that other class listen to it and react accordingly. It’s just like implementing a delegate in another class.

      I’ve seen small changes in the StoreKit framework, but I hadn’t seen that Apple have implemented their own check for switched off purchases. That’s good news for us, because it means less coding. If you’ve tested it and my method is never called, feel free to leave it out. Thanks to the heads up!

      I’m planning to record an updated version of this tutorial, featuring downloads and partial restores too. I can’t give you a timeframe yet, but watch this space 😉

      1. Hi Jay, Thanks for getting back to me. I see what you mean about triggering a notification within the alert controller’s block, and then detecting it within the view controller – I’ll get that implemented shortly.

        I’ll also remove the “cantbuyanything” method too, although I’ve not tested it in iOS versions older than 9, so it may be that it’s only in 9 that it doesn’t get called!

        Thanks again for the quick responses, it’s much appreciated.

        1. Hi Jay, Thanks for getting back to me. I see what you mean about triggering a notification within the alert controller’s block, and then detecting it within the view controller – I’ll get that implemented shortly.

          I’ll also remove the “cantbuyanything” method too, although I’ve not tested it in iOS versions older than 9, so it may be that it’s only in 9 that it doesn’t get called!

          Thanks again for the quick responses, it’s much appreciated.

  9. Hi Jay,

    Thanks for the articles. I was able to implement them into my code and get the UIAlertView to show with the buttons; however, in my debugging I keep getting:

    SKProductsResponseInternal::_invalidIdentifiers = (_NSCFArray *) @”1 object”

    That of course is the _productIdentifiers[0] from my SKProductsRequest.

    A few pieces of information that you will need to being assisting will certainly include:

    – i do have in-app purchases defined in itunesconnect that show product ids which i have copy-pasted into the _allProducts parameter set in Shop::allProducts()
    – i do have a contract set up with bank and tax info. it does show Status as “Processing” in itunesconnect, Agreements Tax and Banking
    – i have actually also tested your code as-is and found that it does return the product
    – if i put my product id in your code it is not returned as a valid product
    – if i put your product id in my code it is not returned as a valid product

    I’m guessing there is a problem in the itunes connect setup and/or in the capabilities section in xcode.

    Any initial thoughts/questions?

    1. Hi larjohns,

      My only thought is that if your product identifier is indeed valid, and the App Store Returns it as invalid, it may be because your bank and tax info hasn’t processed yet. You’ll get an email at that point, I’d try again then.

      The demo project should still work out if the box, as long as you replace my product ID with your own, and leave the deployment target as it is.

  10. Thanks Jay – the bank info and contract show as in process. since it’s been that way for a week, i contacted apple though itunesconnect. i’ll report progress.

    Meanwhile, what would have to be changed in my code to allow the com.versluis.buyme.screencast product to work in my code (to allow me to continue programming while we wait on apple)?

    1. I’m not sure if there is anything you can do apart from wait for Apple to process your application. If you’re not setup to receive payments, I guess they won’t let you test the system.

  11. Gotcha.

    Can you help me understand what I’m missing here. If I

    – change the Bundle id of my project to com.versluis.buyme
    – request the com.versluis.buyme.screencast product

    it does not find the product. What else is required to find the screencast in-app purchase?

    1. The most likely explanation is that the provisioning profile for that bundle ID has expired on my account. Usually you’d replace that with your own so that you have full control over you app, but I understand your situation.

      Let me check on that profile tomorrow. As soon as I renew it, you should be able to use my bundle ID for testing.

    2. OK, I’ve just renewed the provisioning profile, and the app seems to run fine on my drives as it is in the GitHub project. That’s good news!

      However, a small flaw in my thinking occurred when I responded to you last night: even with the refreshed profile, it won’t be any good to you because my profile does not contain your device UUID (d’oh!). Hence, you may still get an error when you try to run with my bundle ID and IAP ID. Your best bet is to recreate those on your own account, replace them accordingly, and test once Apple approve your payment contracts.

      Keep me posted!

Leave a Reply

Your email address will not be published. Required fields are marked *