Update: MKStoreKit 4.0, an updated version of the one presented here is available. Please check it out and use 4.0 instead of this.
Update: A Chinese translation is available here.
Last week, Apple announced that in-app purchases will be available for free apps as well. This could probably free developers from creating “lite” and “pro” versions of the app and allow developers to “unlock” features inside the app and create business models that the AppStore haven’t seen. This model could be a great boon for developers like us to upsell our apps (provided they are of good quality) and to reduce piracy. In this article, we will look at how to incorporate StoreKit to do In-App purchases for your iPhone Application.

Update: Did it really free you from creating “lite” and “pro” versions? How did you manage to give away free copies of your in-app purchases for reviewers? Read my tutorial on how toenable in-app purchases for free

Apple allows three types of purchases within the app and Apple terms them as consumables, non-consumables and subscriptions.

Consumables are products that are “consumed” immediately. This means, if the purchase is made today, and the user wants to purchase it again tomorrow, he will be charged again when he attempts a purchase.

Non-Consumables are features that are purchased exactly once. Apple automatically takes care of “remembering” those purchases and allows the user to purchase them again for free, just like downloading apps you already purchased.

Subscriptions are the most complicated part, They behave like non-consumables during the subscribed period and like consumables after that. You as a developer have to ensure that anything that is subscribed by the user is available across all of his iTunes synced devices when they are purchased from one device. Hence, do not lock in-app purchases to UDIDs. This might even get your app rejected. The StoreKit, as on date, doesn’t have any built-in mechanism to do it automatically which is why subscriptions are a bit tougher to develop.

One important point to note is that, in-app purchases cannot be used to deliver product updates. Changes to the binary has to be separately submitted. However, if you are a game developer, game data, maps, levels and other “data files” are allowed for in-app purchase.

In this post, we will focus on how to prepare your app for enabling features for the “pro” version from the “lite”. Or technically, we will focus on how to bring in, consumables and non-consumables into your app. We will leave the subscriptions part to another blog post as it’s quite complicated and involves some server side programming as well.

Preparing your iTunes Connect

To start with, in-app purchases, you need to do some ground work on your iTunes Connect account. A three step process that Apple thinks every developer should know. (Unfortunately I couldn’t find any official documentation for this)

Step 1:

First is to create an App ID and enable in-app purchases for that. This App ID shouldn’t have any wild card characters or else, the in-app purchases option will be grayed. I would always recommend to use a different App ID for every application you create.

Step 2:

Create provisioning profiles (Development and Distribution) using this App ID. Again it’s a good practice to create different provisioning profiles for every app. There are many tutorials on how to create this here and Apple’s own documentation here (This link will prompt you to login).

Step 3:

You need to create product references in your iTunes account. Each individual in-app purchase should be uniquely identifiable. Apple recommends using the reverse DNS notation, something like, com.mycompany.myiproduct.ifeature Before creating product ids, you need to associate it with a existing application in AppStore. If your app is not yet live, you can create a dummy, placeholder application, fill in the metadata (which you can anyway change it later) and check “upload binary later”.

To create a new in-app purchase, open your itunes connect and choose “Manage In-App purchases”. Choose the app for which you want to setup in-app purchases and click next. You should see a screen like this.

iTunes Connect in-app Purchase

The reference name is the name that appears during the in-app purchase prompt. Any name like, Levels 10 – 50 will be fine. The Product ID should be unique. This is used for reporting as well as within your app for requesting a purchase (more on this later). You can select the type as consumable or non-consumable. When you say an in-app purchase is consumable, your users will be charged everytime they purchase it. This is perfect for a radio app that requires users to pay for listening to a song everytime. If it’s a product feature, set it as non-consumable. Non-consumable products are purchased exactly once. When the user attempts to purchase it again, it will be delivered to him for free.

Type in the other required detail in this page and click save.

Step 4:

The fourth and final step is to create test user accounts. After you program the app, you might want to test the app. You can use these accounts to login to the App Store. The purchases will be processed as if it were real but no financial transactions will take place.

This completes your iTunes connect configuration. Take a deep breath. We have just started. A lot more to go.

Writing the StoreKit Code

Now that you have setup the iTunes account, let’s start by writing the actual code to interact with the AppStore and allow users to make purchases. For coding help, nothing beats the Apple’s official StoreKit programming guide. However, the guide has one bug that crashes the program. We will see how to circumvent it properly here.

Step 1: Adding StoreKit.Framework

The first step here is to add the StoreKit.Framework to your project.

Step 2: Parental Controls

It’s important to check whether the iPhone/iPod doesn’t have parental control restrictions. When you try to initiate a purchase when parental controls are on, you might crash your app. The apple docs code seems to have an error here. The function, canMakePayments is a static method of class SKPaymentQueue and not a member function. The working code looks like this.

if ([SKPaymentQueue canMakePayments])
{
... // Display a store to the user.
}
else
{
... // Warn the user that purchases are disabled.
}

Step 3: Retrieving the product information and populating the UI

Now the you have designed a gorgeous looking view, you can show it to the user using, say presentmodalviewcontroller or any similar method. Do note that StoreKit doesn’t provide the UI to be displayed. It’s upto the developer to design the UI. The first step is to query your “In-App Purchases” and show the user, the available list of options. Retrieving the product information from AppStore is a couple of lines of code as illustrated here.

- (void) requestProductData
{
SKProductsRequest *request= [[SKProductsRequest alloc]
initWithProductIdentifiers: [NSSet setWithObject: kMyFeatureIdentifier]];
request.delegate = self;
[request start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:
        (SKProductsResponse *)response
{
NSArray *myProduct = response.products;
// populate UI
[request autorelease];
}

The kMyFeatureIdentifier you pass to initWithProductIdentifiers is the uniquely identifiable product id you created in your AppStore account. Remember the reverse DNS product id? You CANNOT specify a wild card character here. So, if you have multiple products, you have to initialize the request object with a list of product using

SKProductsRequest *request= [[SKProductsRequest alloc]
initWithProductIdentifiers:
[NSSet setWithObjects: myGreatFeature1, myGreatFeature2, nil]];

You can pass as many features as possible to setWithObjects and be sure to end the last object with nil.
Setting the delegate to self and calling the start method will invoke the “didReceiveResponse” delegate. The delegate will give you an array of products and the request itself. Use the array to populate your store UI and release your request here. (This is the same request you created initially).

Step 4: Adding a Transaction Observer

This is a very important step. You can do this as soon as your app is open or when you start a “In-App” purchase session. Do note that, in-app purchase requests are continued even if the user quits the app in between. So imagine a case, when user buys an item, but before the transaction is processed, he gets a phone call that interrupts everything. Though the actual transaction is not interfered (as it happens on Apple servers), your application will never know what happened. To ensure that you get all transaction notifications, (completed/ pending/restored), you have to register a class that receives the callbacks from AppStore. This class should implement and it’s delegate methods.
This is the code for registering the your store observer.

MKStoreObserver *observer = [[MKStoreObserver alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:observer];

(If you can’t follow anything here, just head below for the real source code, but it’s advised that you read through this, understand and then use the code in your app).

Step 4: Implementing the callback

Within your MKStoreObserver class, you have to implement the callback function paymentQueue:updatedTransactions:

This function will receive updates on the transactions as and when it’s made. Because your transactions take place even when the app is closed, you should be ready to receive these notifications as soon as you open the app. So the best place is to initialize it in applicationDidFinishLaunching or equivalent method.

Now in the updatedTransactions functions, handle the three types of transactions, purchased, failed and restored.

- (void)paymentQueue:updatedTransactions(SKPaymentQueue *)queue
updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
// take action to purchase the feature
[self provideContent: transaction.payment.productIdentifier];
break;
case SKPaymentTransactionStateFailed:
if (transaction.error.code != SKErrorPaymentCancelled)
{
// Optionally, display an error here.
}
// take action to display some error message
break;
case SKPaymentTransactionStateRestored:
// take action to restore the app as if it was purchased
[self provideContent: transaction.originalTransaction.payment.productIdentifier];
default:
break;
}
// Remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
}

Purchase and failed are seemingly straightforward. You will receive a restored transaction message when your app was quit before the transaction was completed. You should always do the “same” thing when your purchase is new or restored. If you want to charge your users for every download, then probably, set the in-app purchase to be a “consumable” item. But be sure to use that only for purchases that are really “consumable”. Like a live radio show or a podcast and not for unlocking additional levels. Users expect that a level they have unlocked will stay forever.

Three things to note here
1) You should remove the transaction from the payment queue after the transaction is complete. Otherwise, the transaction will be re-attempted, which is not what the users expect (and your app will most likely get rejected).

2) You should provide the content (or unlock the feature) before completing the transaction. When you receive the message SKPaymentTransactionStatePurchased, it means that the users’ credit card has been charged. It’s high time that you provide the feature.

3) You should not display an error when the transaction fails because the user rejected it. Display any error message only when,

if (transaction.error.code != SKErrorPaymentCancelled)

Apple recommends you not to display an error, because that is not an error. The user has purposely cancelled the transaction (probably because the price was too high?). You can audit it and go on. But for heaven sake, don’t display an error like, “Unable to process transaction because user cancelled operation!”. It will be soooo Windozy…

Step 5: The actual purchase

Now that your architecture is ready, you can go ahead and initiate the purchase by calling the function below when the user clicks your “Buy” button on the UI.

SKPayment *payment = [SKPayment paymentWithProductIdentifier:myGreatFeature1];
[[SKPaymentQueue defaultQueue] addPayment:payment];

Optionally, you can add something like payment quantity for “consumable” items.

payment.quantity = n; // number of "items" that user wishes to purchase.

Finally, after providing the feature, you should “remember” that the user has purchased the app. Apple’s recommended way is to use NSUserDefaults, the same way you store your settings.

Testing your app

Alright. Now let’s test the app. Note that, the app cannot be testing from iPhone simulator. The StoreKit communicates with AppStore.app to complete transactions which is not present in the Simulator. So connect your iPhone and run the app.
Remember step 3 you did in iTunes connect? You created some test accounts? Well, they are used for testing your app. Before using that, sign out of AppStore by opening Settings.app -> Store -> Sign Out.
Start the app. (You should NOT sign into the AppStore with the test user account. It will anyway ask you to provide your credit card which we are not interested in)

Open the Store UI and initiate the purchase. You will get a prompt like, “Do you want to buy 1 “ABC feature” for 2.99$? Tap Buy. You will be prompted to login. Provide your test account login. The AppStore provides a secure connection to the iTunes account and notifies you whether the purchase was successful through the callback paymentQueue:updatedTransactions. When you use the test account, the scenarios will be exactly same expect that no one will be charged. These test accounts run inside a sandbox.

In case your app got quit by a phone call, the transactions continue and you will get a restoreTransactions the next time your app is opened. This is why you should start listening to transactions as soon as you open the app (not just when the user opens the store UI)

That’s it. I wouldn’t say its easy. But for developers who have some intermediate knowledge in iPhone development and Objective C, it shouldn’t be a big deal. Remember that when your app is free, you get 10 times more downloads (as reported by admob statistics). When people actually use your app, there is a high chance that they buy your in-app features. That’s upselling becomes easy. Given that this is a very strong business model for the already saturated AppStore, you should start incorporating this model into your code soon.

Source code

The source code, MKStoreKit, contains four files. MKStoreManager.h/m and MKStoreObserver.h/m. The StoreManager is a singleton class that takes care of *everything* Include StoreKit framework into your product and drag these four files into the project. You then have to initialize it by calling [MKStoreManager sharedStorageManager] in your applicationDidFinishLaunching. From then on, it does the magic. The MKStoreKit automatically activates/deactivates features based on your userDefaults. When a feature is purchased, it automatically records it into NSUserDefaults. For checking whether the user has purchased the feature, you can call a function like,

if([MKStoreManager featureAPurchased])
{
//unlock it
}

To purchase a feature, just call

[[MKStoreManager sharedManager] buyFeatureA];

It’s that simple with my storekit. The source code will be uploaded when this post is read by at least 1000 people. Please spread the word.

As always, all my source code can be used without royalty into your app. Just make sure that you don’t remove the copyright notice from the source code if you make your app open source. You don’t have to attribute me in your app, although I would be glad if you do so :)

Downloads:
Update: MKStoreKit 4.0, an updated version of the one presented here is available. Please check it out and use 4.0 instead of this.

Version 2:MKStoreKit V2.0
Version 1:MKStoreKit.zip

Troubleshooting

Despite all this, In-App Purchases remain a biggest and the most PITA situation for any iPhone developer. If you can’t get it work, check whether your “didReceiveResponse” delegate returns the product id you passed as invalid. You can confirm this by adding a NSLog statement inside the delegate. Double check if your invalid product id returned here matches the product id you created in iTunes connect. If they are same, check if your product id on iTunes connect says “Cleared for Sale”. For this, you have to provide a screenshot and “Developer Approve” it.

Another case is, if this is your first app, then chances are that, your “Paid Applications Contract” isn’t yet in effect. If this is the case, you have to wait till Apple approves your bank details.

If these two doesn’t work, you might have to wait for 12-24 hrs, till Apple propagates your iTunes connect information to all it’s servers. See the last line in this documentation for more details.

If you have issues adding this to your application, you can hire me to do it for you. I charge a nominal fee of $350 – $700(depending on the complexity) for the whole integration and it should take approximately half a day to one day. You can also approach me for a customized code that suits your business model as well.

Update 1: (22-Oct-2009): Code changes to fix a crash that occured in most cases.
Update 2: (7-Dec-2009): Added link to MKStoreKit v2.0.
Update 3: (4th Dec 2010) MKStoreKit 3.0, an updated version of the one presented here is available. Please check it out and use 3.0 instead of this.
Update 4: (8th July 2011) MKStoreKit 4.0, an updated version of the one presented here is available. Please check it out and use 4.0 instead of this.

Support me

Hourly rates of a iPhone developer is skyrocket high. I believe this code would have saved your coding hours by at least a day. You can consider supporting further development by funding me through PayPal.  My PayPal email is mugunth.kumar@gmail.com

Mugunth

Follow me on Twitter

  • gary

    I downloaded the code, can build and compile fine. I have signed out of store on my device but when I call the buyFeatureA it doesnt actually ask me to login to itunes at all so I dont get to enter one of the test in-app purchases I created.

    Not sure what is wrong?

    • mugunthkumar

      Should be a configuration problem on iTunes connectMugunthSent from my iPhone

    • Felix

      Hi, first i wanna say thank you for this nice work you have done.

      But i am stucked with the same problem like gary.

      I’ve done all steps to my iTunes-Connect like its posted in your tutorial.

      I renamed the featureId’s like in my itunes-connect.

      So i build up a one button-inApp-Test-Application.

      The Button calls the buyFeature:fatureAId function.

      So through NSLogs i see the Program goes to the

      “if ([SKPaymentQueue canMakePayments]) {

      ….

      }

      but after that nothing happens… :(

      I can fire this function as often i want, but still nothing happens…

      so you got an idea what i did miss?

      Best regards

      Felix

  • SpinalJack

    Hi, great post, I was wondering what changes need to be made to alter this code for use with consumables? i.e. it wont check if you've bought it before and just charge the user again when he clicks buy

    • SpinalJack

      I've set up iTunes Connect with consumables and I keep getting "this product has already been bought but not downloaded, click to download" and then if you click OK it gets transfer failed.

      Is there something in the code that needs changing to consumables?

      • SpinalJack

        Okay, figured it out, I had to reset the user defaults to NO if I want to buy the pack again

  • Hemant

    great tutorial..i created in app purchases in my application with the help of your tutorial. But still my test account doesn’t work fine. When i test my application using test account the sandbox environment asks me to buy the product and after buying it asks me to buy the product again straightaway. Is it some problem while using test accounts or is there a problem in my coding?? this is my first application and figuring out in app purchases for your application can be really hard at times. i have 4 products and this happens only with 1 or 2 products and rest work fine. So i am sure the in app purchases is fine but cant figure out what could be wrong??

  • Patrice

    Hi,

    I was using your soluce, with the featurecheck to enable test from reviewers and all was working very well, thank you for this, it's great…
    But now, under IOS4, the app crash when we click on the in-app purchase button… (no problem under ipad 3.2)
    Is it a general problem or I've done something wrong ? If it's my error, have you some ideas of what can be done wrong ?

    Thank you very much.

    • mugunthkumar

      I'm not facing any such problems so far. Can you explain a bit more?Thanks,MK

      • Patrice

        Thank you VERY much for your quick answer !
        I'm using your soluce on 3 projects (including 1 with phonegap framework).
        The first project submitted was rejected by Apple because of a bug under IOS4, so I installed SDK for it and update my iphone OS4.
        And it's true, the apps are working well under 3.1 and 3.2 but crash when I click on the in-app purchase button.
        I don't find what's the problem !! :(
        I've upped examples of my files : http://www.onveut.com/MKStoreManager.h.txt http://www.onveut.com/MKStoreManager.m.txt
        perhaps I'm blind and can't see what I've done wrong ?

        Thank you VERY VERY much for your help, I'm a bit lost…

        • mugunthkumar

          One of my latest issues with iOS 4 washttp://blog.mugunthkumar.com/coding/ios4-issue-nsurlconnection-and-nsoperation/But it didn't crash the system. Can you give me a crash report or something?

          • Patrice

            The problem seems to come from the function :
            – (BOOL) canCurrentDeviceUseFeature: (NSString*) featureID

            If I remove this server's test, the inapp purchase works… It seems the post is no more working ?
            But, the exact same stuff continue to work on ipad …

          • Patrice

            Hi again, I suppose you don't answer because you have no idea on what's wrong.
            I will aggrave this weird situation :
            A test inspired by cancurrentdevice at the app's launch is working well on iphone os4 simulator… but not on the real device…

          • mugunthkumar

            in-app purchases will not work on Simulator. Test only on devices. Again, JB'ed devices also show weird errors.Second issue could happen if you call the function from a thread apart from MainThread. Read my latest post on the same

          • Patrice

            My iphone is not jaibreaked. The problem encountered is in the post to my server and its answer, I test to use it at the launch :
            – (void)applicationDidFinishLaunching:(UIApplication *)application {
            NSString *uniqueID = [[UIDevice currentDevice] uniqueIdentifier];
            NSString *adresseUrl=(NSString*)[NSString stringWithFormat:@"http://www.myserver.com/pk/featureCheck.php"%5D;
            NSURL *url = [NSURL URLWithString:adresseUrl];
            NSMutableURLRequest *theRequest = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60];
            [theRequest setHTTPMethod:@"POST"];
            [theRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
            NSString *postData = [NSString stringWithFormat:@"productid=%@&udid=%@", featureID, uniqueID];
            NSString *length = [NSString stringWithFormat:@"%d", [postData length]];
            [theRequest setValue:length forHTTPHeaderField:@"Content-Length"];
            [theRequest setHTTPBody:[postData dataUsingEncoding:NSASCIIStringEncoding]];
            NSHTTPURLResponse* urlResponse = nil;
            NSError *error = [[[NSError alloc] init] autorelease];
            NSData *responseData = [NSURLConnection sendSynchronousRequest:theRequest returningResponse:&urlResponse error:&error];
            responseString = [[NSString alloc] initWithData:responseData encoding:NSASCIIStringEncoding];
            if([responseString isEqualToString:@"YES"])
            {
            if(flagI==0)
            {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"pk" message:@"You can use the application" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alert show];
            [alert release];
            flagI++;
            }
            }

            if([responseString isEqualToString:@"NO"])
            {
            if(flagI==0)
            {
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"pk" message:@"You cannot use the application" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [alert show];
            [alert release];
            flagI++;
            }
            }
            if([responseString isEqualToString:@"YES"])
            {
            [window addSubview:viewControllerMain.view];
            [window makeKeyAndVisible];
            [responseString release];
            }
            else
            {
            [window addSubview:viewController.view];
            [window makeKeyAndVisible];
            [responseString release];
            }
            }
            }

            It works on Ipad, on iphone 3.1, on simulator but not on iphone OS4…

            So long days searching the problem without any success…. :(

            Thx for your help.

      • Patrice

        Thank you very much for your quick answer.
        I'm lost.
        Work well on 3.1 and 3.2 but crask when I click on the in-app purchase button.
        I've uploaded files : http://www.onveut.com/MKStoreManager.h.txt and MKStoreManager.m.txt
        Perhaps you can see where's the problem ?
        Thx again an lot for your precious help.

    • Patrice

      I was restarting from zero, following your tutorial again and I have the same problem : iphone crash. In the console, I have :
      terminate called after throwinf an instance of NSexception
      Program received signal : "SIGABRT"

  • Patrice

    on device, the app crashe or freeze when I click the button to buy in-app purchase… On the console, I've just "GDB interrupted".
    On the simulator, it crashes with this in console : SKProductrequest 0x6d44990 failing immediately in simulator

  • mobidev

    I have a few questions regarding inApp Purchase as follows:

    i) Do we need to make a product (in App purchase) live before submission or we can make it after app approval.
    Suppose I have a product in inApp Purchase that is to be in sale by Next week, and if my app with inApp purchase version gets approved this week, then how do the Apple store test my app.

    ii) Do any one know how the apple app store guys test the inApp purchase in the application. What does the screen shot submitted to approve the product in iTunes for inApp Purchase refers to.

  • Shakti Pardeshi

    Hi MK
    i just want to know from where i can download the latest code for in app purchase tutorial uploaded by u.
    Also how can i fetch product details from app store at the launch of my application?

    • mugunthkumar

      Mkstorekit v2.zip is attached to the blog post itself under the “source code” section.Fetching product details is automatically done by the code.Sent from my iPhone

      • Shaktising Pardeshi

        Ok thanks a lot.
        Actually what i have to do is, i have to fetch particular data from App store at the time of application launch. so how can i distinguish ? Their is only app and under that app i have so many product's (features) so first i have to fetch all the details of features and upon selection from user, i have to buy that particular feature. If i have to send u screen shot for above description, where to send u?

  • Shakti Pardeshi

    Hi MK
    When i m sending the product identifier to get the product information, i didn't get any thing. the purchasableObjects array is returning 0 object. why is it so? pls reply asap, i have to submit the build by 2maro.

  • Shakti Pardeshi

    Hi MK,

    I am getting the product info from App Store and storing that info to my DB. Using this info i m displaying the data in a table with Product name assigned by me along with its price. For single item purchase it is working properly. How to provide multiple item purchase to user? Pls reply.

  • Flo

    Hi,

    I can open my store only one time. If I try to open Store a second time, it crashes. This is because of the following code.

    + (id)allocWithZone:(NSZone *)zone
    {
    @synchronized(self) {
    if (_sharedStoreManager == nil) {
    _sharedStoreManager = [super allocWithZone:zone];
    return _sharedStoreManager; // assignment and return on first allocation
    }
    }
    return nil; //on subsequent allocation attempts return nil
    }

    Is it an important part of the code. Can we erase it? Thanks

  • Shakti

    Hi MK,
    I have asked for this before also but didn't get any reply from u.
    I stuck with the multiple item purchase using In App Purchase. I search a lot over net but didn't find anything helpful. Do u know how to send multiple item purchase to App Store in a single purchase request?

  • Pingback: In-app purchasesthe iPhone Developer | the iPhone Developer()

  • shan

    Thank you Kumar for your excellent tutorial and wrappers. I have one question. During the testing phase, when I call [[MKStoreManager sharedManager] buyFeature:[product productIdentifier]]; when use click on a button . It takes around 3-4 seconds to open up the popup to confirm/cancel the purchase. During that time, use can click on button for multiple times and this creates a duplicate purchase request. Is there any standard way to prevent that? Should we show some kind of blocking ui. And when to remove the blocking ui?

    Thank you for your help.

    • mugunthkumar

      You can disable the button…Sent from my iPad

  • Kyle Buttress

    Hello, I am using yout classes in my app code for in app purchase, I've used it previously and has been working.

    This time I continue to get Transaction Error?

    Error Domain=SKErrorDomain code=0 UserInfo=hex number?? cannot connect to iTunes Store

    have you had reports of this issue recently?
    I'm using it in iPad app?
    thanks
    Kyle

    • I´m having the same problems. Did you solve it yet?

  • Rob

    Thanks for the great tutorial! So far everything is working very well. The only thing I added was an NSNotificationCenter item so I can tell my UI to unblock the purchase button and pop a view controller. You may want to consider adding that as functionality in the future. Other than that, this has been one of the easiest and best designed wrappers I've come across.

    Thanks again for your generosity! You should really consider placing PayPal "Donate" buttons on your posts :)

    • mugunthkumar

      Thanks for your feedback! I will surely add a donate button soon. Meanwhile, you can donate any amount you like to mugunth.kumar@gmail.com :-)Sent from my iPad

  • Nicklas

    Hello
    Genious tutorial and code.
    I have a problem regarding the transaction.
    I have followed you steps, initializing, changing featudeId's and making a buyFeature.
    Still the failed transaction is beeing called. I noticed that by using Alerts.
    Is this a problem with my ID's or what should I do to fix this?

    /Nicklas

    • Nicklas

      YES it works! But where should I put a notification/animation or what I now want to notify the user that the purchase has been done?

  • Pingback: Adding In-App-Purchase Support: Avoid AppId Troubles « Alexandre Gomes()

  • serenhjkim

    thank your posting. i really appreciated it.
    but i have a problem. i got stuck it for several days. i got crazy.
    my apps return "SKErrorPaymentInvalid" all the times.
    i made 3 sample apps. all apps occurred error.

    any help??

  • I keep getting this error telling me that 'You've already purchased this In App Purchase but it hasn't been downloaded' error….. http://yfrog.com/eq54ij

    I was wondering if it's something on apple's server? Or am I doing something wrong that would be causing this? I tried multiple accounts, I've tried installing reinstalling the app ?!? Also, it worked completely well up until last night… I tested it over and over again with one account, then it just quit working.

    Is there anything that you could recommend?

    • Michael

      I've got the same problem, always the same "You've already purchased…" message. Maybe you are right that it's an Apple server problem?

    • I´m having the same problem with a consumable product. How do you notify Apple that the product has been downloaded?

  • hi
    thank you for your article.
    i have a question.
    what's a "ownServer" in MKStoreManager file.
    please tell me a stepwise direction.

  • Saktheeswaran

    Hi Mugunth Kumar,

    Ur code is working good. While testing i got the message as "Your purchase was successful" [Sandbox Environment].

    My question is, Is this code will automatically deliver the product to the user after Apple approved our InApp Purchase. or we have to write any other code for delivering product to the user.

    Please reply quickly,
    we are waiting for your reply to upload the InApp Purchase.

    Thank you

    • Umaid

      I have the same query as ur please reply to me asap

  • Ritesh

    Hi MK,

    Thanks for such a useful tutorial about in app purchase. I had implemented in-app purchase in one of our application couple of days back and it was working perfectly fine as I had built it with SDK 3.1.2. I had also uploaded the app on app store. Now I am trying to build the same application with SDk 4.0 and trying to uplaod it on a different developer account but somehow I am not getting the Pop up for purchasing the Pro version of my app though I am getting all information about product with NSLog(@"Feature: %@, Cost: %f, ID: %@",[product localizedTitle]. I have created a test user for app too to test the in app purchase in sandbox environment.

    Can you please let me know if there is any change you have made to build it for SDk 4.0

    Thanks.
    Ritesh C patil

  • Hi
    I just want to know something.My app is done and I am providing 10 tasks initially for more than 10 tasks user must buy the new binary for it.I want to know whether we can provide new binary via In App Purchase?
    Please help soon.

  • petem

    Hi, I appreciate your work here. I've downloaded V2. Can I suggest that it needs some delegate methods of its own, since one has to get in there and customise it, eg what happens when product list arrives, the number of products. But it's a good start and I'll be to make it work for me.

    One question for now, I hope it's going to work for the style of product which doesn't require checking productId/udid at a server. The flow of the code if I leave that ownServer variable nil, looks to throw up an uialert. I just want to add unlock code features with the purchase.

  • Pingback: MachWerx » Blog Archive » In App Purchases()

  • Robert

    Hi Mugunth,

    Thanks so much for the great tutorial. I'm getting stuck at trying to export the price information from the MKStoreManager to my main .m file. In the productsRequest: didReceiveResponse: method I use NSNumberFormatter to do the following:

    NSString *featureAPrice = [numberFormatter stringFromNumber:product.price];

    When I NSLog(featureAPrice) I get the correct price.

    But for some reason, when I access featureAPrice later, it returns "keypath" instead of the correct price. Any thoughts on this would be immensely helpful.

    Thanks!
    Robert

  • Who would want to go on a full time diet ,anyone?. Eat however much you want, just please rememebr to keep excercising

  • Markus

    Hello

    great Tutorial. 2 days left for appstore upload. In sandbox everything works fine. I implemented a better way to register purchased items on my dev server. I used ASIHttp for that.

    One thing i do not understand. The usage of shouldSerialze=YES in

    if(serialize)
    {
    if([_delegate respondsToSelector:@selector(productPurchased:)])
    [_delegate productPurchased:productIdentifier];
    ….
    }

  • Anna

    Thank you so much for the post! I am able to get my products, my problem comes when I try to purchase.

    I am getting into updatedTransactions with one transaction, however my transaction.transactionState (and all other data for the transaction) is null. In addition, I am never asked for my iTunes info.

    Any ideas?

    Thanks again.

  • zfisher323

    This works great in my app, but it seems to be working pretty slowly (a 10-15 second delay when I press the "purchase" button before anything happens). Is this slowness on Apple's end or something I can change in the app?

  • Pingback: Introducing MKStoreKit – Version 3 | MK Blog()

  • Vijay Shankar

    Hi Mugunth Kumar,

    Thanks for this wonderful tutorial.

    We created an app in the developer portal as ‘Main app’ with the product id as com.companyname.mainapp and also two inapp purchase apps as ‘Sub app1′, ‘Sub app2′ with the product identifiers as com.companyname.mainapp.subapp1 and com.companyname.mainapp.subapp2.
    We wrote the code to handle the payment and once the transaction state reaches SKPaymentTransactionStatePurchased.
    It is the responsibility of the apple to download and install the Sub app1 in the device? or do we need to write a code to install the sub app1 or sub app2 in the device.
    Note: We use the in app store inside the main app ie we have sub app1, sub app2 with the buy now button.
    Another question : After we purchase the Sub app1. Do we need to show as buy now inside the Main app for Sub app1 or show the status or button as Installed?

    Thanks,
    Vijay

  • Max

    Hi,

    Thanks for all the tips and tricks. I searched the web to find out how long the typical review process for a non-Consumables product is but had no luck.
    What’s your experience on that? Is it the same review line as for apps? Does it take hours or days for a non-consumable product to be available?

    Thanks for any hints on that.
    Martin

    • Anonymous

      A non consumable shouldn’t affect approval time

      Sent from my Windows Phone From: Disqus
      Sent: Monday, 6 December, 2010 1:13 AM
      To: me@mk.sg
      Subject: [mkblog] Re: iPhone Tutorial – In-App Purchases
      ======

      • Max

        Thanks for your answer. The question is how long does it take for Apple to review a new “non-comsumable” product. Let’s say I’m creating a magazine app and I have a new issue every week.

        If the review process for a new issue is taking longer than a couple of hours it would be a huge problem. In that case we would have to use the subscription model.
        Or is it allowed to create non-consumeable products in advance, let those review and activate them later on our servers? (doesn’t make sense I think…)

  • Vijay Shankar

    Hi,

    I am having the problem in delivery the inApp product (purchased product identifier). Can you help me in getting the sample code to deliver the product after purchase confirmation as how the AppShopper app(in iTunes Store) works.

    Thanks,
    Vijay

  • Ausmanager

    I’ve just recompiled using 4.2 and in-app stopped working (it doesn’t pop up 2nd question just before the purchase). It worked in 3.2 and 4.0.

  • Ausmanager

    Could be false alarm. We also changed Identifier. Could be that Apple store is ignoring request and MKStore is not getting any notification. Yet to confirm.

  • vijay shankar

    Hi All,

    I created about 10 products using in app purchase for my bundle id. The apple team reviewed my in app purchase app and the 10 products shows in review. It seems the review team tested my app and they said they’ are not able to see the products installed in the device after successful “Thank you for purchasing the product” message. Do we need to wait for the products to be approved by the apple team? or is there any other problem with my code or stuff like to contact apple. I tried contacting the apple team , but no appropriate response from them. Can any one help me on this?

  • Shumais

    Hey Man!
    Thanks a lot for the great effort that you have put in here, it really saved me a lot of time.
    I do have a question though,
    In MkStoreManager.h ::

    // CONFIGURATION STARTS — Change this in your app
    #define kConsumableBaseFeatureId @”com.mycompany.myapp.”
    #define kFeatureAId @”com.mycompany.myapp.featureA”
    #define kConsumableFeatureBId @”com.mycompany.myapp.005″
    // consumable features should have only number as the last part of the product name
    // MKStoreKit automatically keeps track of the count of your consumable product

    can you tell me what each variable represents??
    I am confused about kConsumableBaseFeatureId and kConsumableFeatureBId…Both say Consumable, shouldnt one of those be Non Consumable?? I mean, we have kFeatureAId for the subscription, like wise we should have pne for Conusmable and one for Non Consumable?

    Am I right? If not, then how do I handle NonConsumable items?

    thanks!

    Shumais Ul Haq

    • TimE90

      Same question here.

      And I also get the error message:
      *** Terminating app due to uncaught exception ‘NSRangeException’, reason: ‘*** -[NSCFString substringFromIndex:]: Range or index out of bounds’

      I only have one NonConsumable feature, how to configurate the MKStoreKit?

  • Airport Life

    I am creating my first app and have a question about my revenue model satisfying Apple’s guidelines. The app is a travel app that has basic features and premium features (automatic flight itinerary changes updating, etc…) that can be unlocked by paying a subscription. The user can buy a 30 day, 90 day, and one year subscription to unlock the features. If/when the user stops paying the subscription, the premium features re-lock. Is there any reason this model wouldn’t be approved by Apple?

  • Lee

    This tutorial is so good. I also found the similar example below.

    The In-App Purchase Sample above works fine on certain devices, but some are not.

    I tested 4 devices which are as follows:

    1. iPod Touch1 16G iOS 3.1.3 works fine (registered device)
    2. WiFi iPad 16G iOS 4.2.1 doesn’t work (registered device)
    3. iPhone4 16G iOS 4.1 doesn’t work (not a registered device)
    4. 3G iPad 32G iOS 4.2.1 works fine (not a registered device)

    The devices doesn’t work appearing the messages “No products available.” and subsequently showed the message “An error encountered” in console window during testing period.

    So, what happened on the method below? Or maybe there are some other reasons causing this problem.

    (void)productsRequest:(SKProdu­ctsRequest *)request didReceiveResponse:(SKProducts­Response *)response
    According to the website info below, the only one thing I haven’t done that yet is to upload the binary file. http://troybrant.net/blog/2010/01/invalid-product-ids/

    Because, I saw the Apple’s official webpage said that as follow:
    “Must I upload a binary to test In App Purchase?
    No. Testing In App Purchase does not require uploading a binary.”

    How to solve this problems?
    Can somebody answer this question, I’ll definitely so appreciate about that.

  • Pingback: iPhone разработка: Интегрируем In-App Purchases | Full news for everyone!()

  • SoCal

    Great blog, Mugunth!!!!

    Could you do the tutorial on the Subscriptions (the toughest part, when you can) so if any of us wants to implement that in the future would know what to do?

  • Gamut

    mugunkumar

  • Gamut

    Hey mugun, this code doesnt work.

    Sam

  • Pingback: Blog What I Made » iOS In-app purchases, week 156()

  • Jangelo42

    OIs there a way to test using the simulator but with stubbed out calls to app store so i can test the flow before I upload the app to the app store and test in the sandbox?

  • Javi

    Thank you for the code.

    I have a doubt… now, I can buy inapp and control if the inapp has been purchased when the app closes and reopen… but I cant detect if the inapps has been already purchased when I uninstall and reinstall the app.

    How can I do it? must be a method to ask Apple if this inapp has been bought…

    Thanks

  • Pingback: is it necessary to set up all banking account info in the iphone dev account before submitting a InAppPurchase free application. | taking a bite into Apple()

  • Mohd Imran

    Hi MK,

    I download your source code and implement it in my project but getting this message “Problem in iTunes connect configuration for product”. I am new in iPhone development. I followed every step to tell here.

  • Pingback: Digi Social Squeeze – Expert Review()