본문 바로가기

iPhone dev.

In-app purchase 정리

*iTunesConnect가 변경되었기 때문에 사용자를 추가할 때 단순히 tester를 추가하는 것이

아니라 sandbox tester로 추가해야 됨



link: http://stackoverflow.com/questions/19556336/how-do-you-add-an-in-app-purchase-to-an-ios-application

How do you add an in-app purchase to an iOS application?

How do you add an in-app purchase to an iOS app using XCode 5 or 6 using iOS 7 or 8? What are all the details and is there any sample code? (Question and Answer style, answered by me below)

share|improve this question
5 
What about reading the "In-App Purchase Programming Guide"? –  rmaddy Oct 24 '13 at 4:24
   
1 
@rmaddy: it helps to read different people's takes on a same problem. –  Zinan Xing Oct 11 at 19:31
up vote123down voteaccepted

The best ways to get an in-app purchase working for iOS 7 (or iOS 8) in XCode 5 or 6 is to do the following:

  1. go to itunes.connect.apple.com and log in
  2. click manage your apps then click the app you want do add the purchase into
  3. click manage your in-app purchases
  4. click create new in the top left hand corner
  5. for this tutorial, were going to be adding a in-app purchase to remove ads, so choose non-consumable
  6. for the reference name, put whatever you want (but make sure you know what it is)
  7. for product id put com.companyname.appname.referencename this will work the best, so for example, you could use com.brainademy.brainademy.removeads
  8. choose cleared for sale and then choose price tier as 1 (99¢). Tier 2 would be $1.99, and tier 3 would be $2.99. The full list is available if you click view pricing matrix I recommend you use tier 1, because that's usually the most anyone will ever pay to remove ads.
  9. Click the blue add language button, and input the information. This will ALL be shown to the customer, so don't put anything you don't want them seeing
  10. for hosting content with Apple choose no
  11. You can leave the review notes blank FOR NOW.
  12. skip the screenshot for review FOR NOW, everything we skip we will come back to.
  13. press save

now that you've set up your in-app purchase information on iTunesConnect, go into your Xcode project, and go to the application manager (blue page-like icon at the top of where your methods and header files are) click on your app under targets (should be the first one) then go to general. At the bottom, you should see linked frameworks and libraries click the little plus symbol and add the framework StoreKit.framework If you don't do this, the in-app purchase will NOT work!

now we're going to get into the actual coding.

Add the following code into your .h file:

BOOL areAdsRemoved;

- (IBAction)purchase;
- (IBAction)restore;
- (IBAction)tapsRemoveAdsButton;

and now add the following into your .m file, this part gets complicated, so I sudgest you read the comments in the code:

#define kRemoveAdsProductIdentifier @"put your product id (the one that we just made in iTunesConnect) in here"

- (void)tapsRemoveAds{
NSLog(@"User requests to remove ads");

if([SKPaymentQueue canMakePayments]){
    NSLog(@"User can make payments");

    SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kRemoveAdsProductIdentifier]];
    productsRequest.delegate = self;
    [productsRequest start];

}
else{
    NSLog(@"User cannot make payments due to parental controls");
    //this is called the user cannot make payments, most likely due to parental controls
}
}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
SKProduct *validProduct = nil;
int count = [response.products count];
if(count > 0){
    validProduct = [response.products objectAtIndex:0];
    NSLog(@"Products Available!");
    [self purchase:validProduct];
}
else if(!validProduct){
    NSLog(@"No products available");
    //this is called if your product id is not valid, this shouldn't be called unless that happens.
}
}

- (IBAction)purchase:(SKProduct *)product{
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}

- (IBAction) restore{
//this is called when the user restores purchases, you should hook this up to a button
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
NSLog(@"received restored transactions: %i", queue.transactions.count);
for (SKPaymentTransaction *transaction in queue.transactions)
{
    if(SKPaymentTransactionStateRestored){
       NSLog(@"Transaction state -> Restored");
       //called when the user successfully restores a purchase
       [self doRemoveAds];
       [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
       break;
    }

}

}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for(SKPaymentTransaction *transaction in transactions){
    switch (transaction.transactionState){
        case SKPaymentTransactionStatePurchasing: NSLog(@"Transaction state -> Purchasing");
            //called when the user is in the process of purchasing, do not add any of your own code here.
            break;
        case SKPaymentTransactionStatePurchased:
            //this is called when the user has successfully purchased the package (Cha-Ching!)
            [self doRemoveAds]; //you can add your code for what you want to happen when the user buys the purchase here, for this tutorial we use removing ads
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            NSLog(@"Transaction state -> Purchased");
            break;
        case SKPaymentTransactionStateRestored:
            NSLog(@"Transaction state -> Restored");
            //add the same code as you did from SKPaymentTransactionStatePurchased here
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            break;
        case SKPaymentTransactionStateFailed:
            //called when the transaction does not finnish
            if(transaction.error.code != SKErrorPaymentCancelled){
                NSLog(@"Transaction state -> Cancelled");
                //the user cancelled the payment ;(
            }
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            break;
    }
}
}

Now you want to add your code for what will happen when the user finishes the transaction, for this tutorial, we use removing adds, you will have to add your own code for what happens when the banner view loads.

- (void)doRemoveAds{
ADBannerView *banner;
[banner setAlpha:0];
adsRemoved = YES;
removeAdsButton.hidden = YES;
removeAdsButton.enabled = NO;
[[NSUserDefaults standardUserDefaults] setBool:adsRemoved forKey:@"areAdsRemoved"];
//use NSUserDefaults so that you can load wether or not they bought it
[[NSUserDefaults standardUserDefaults] synchronize];
}

If you don't have ads in your application, you can use any other thing that you want, we could make the color of the background blue. To do this we would want to add

- (void)doRemoveAds{
[self.view setBackgroundColor:[UIColor blueColor]];
areAdsRemoved = YES
//set the bool for wether or not they purchased it to YES, you could use your own boolean here, but you would have to declare it in your .h file

[[NSUserDefaults standardUserDefaults] setBool:adsRemoved forKey:@"areAdsRemoved"];
//use NSUserDefaults so that you can load wether or not they bought it
[[NSUserDefaults standardUserDefaults] synchronize];

now somewhere in your ViewDidLoad method, your going to want to add the following code:

areAdsRemoved = [[NSUserDefaults standardUserDefaults] boolForKey:@"areAddsRemoved"];
[[NSUserDefaults standardUserDefaults] synchronize];
//this will load wether or not they bought the in-app purchase

if(areAdsRemoved){
    [self.view setBackgroundColor:[UIColor blueColor]];
    //if they did buy it, set the background to blue, if your using the code above to set the background to blue, if your removing ads, your going to have to make your own code here
}

Now that you have added all the code, go into your .xib or storyboard file, and add two buttons, one saying purchase, and the other saying restore. Hook up the tapsRemoveAds IBAction to the purchase button that you just made.

Next, go into iTunesConnect, and click manage users then click test users, and then click add new user you can just put in random things for the name and last name, and the e-mail does not have to be real. You just have to be able to remember it. Put in a password (which you will have to remember) and fill in the rest of the info. iTunes store HAS to be in the correct country, though. Next, log out of your existing iTunes account. (you can log back in after this tutorial) and log in as the test user that you just created.

Now, run your application on your iOS device, if you try running it on the simulator, the purchase will alwayserror, you HAVE TO run it on your iOS device, once you've ran it on your device, click the purchase button, and when it asks you to confirm the purchase of 99¢ or whatever you set the price tier too, TAKE A SCREEN SNAPSHOT OF IT this is what your going to use for your screenshot for review on iTunesConnect. Now cancel the payment

Now, go to iTunesConnect, then go to Manage your apps > the app you have the In-app purchase on > manage in-app purchases > click your in-app purchase, and click edit under in-app purchase details. Once you've done that, import the photo that you just took on your iPhone into your computer, and upload that as the screenshot for review, then, in review notes, put your TEST USER e-mail and password. This will help apple in the review process.

After you have done this, go back onto the application on your iOS device, still logged in as the test user account, and click the purchase button. This time, confirm the payment Don't worry, this will NOT charge your account ANY money, test user accounts get all in-app purchases for free After you have confirmed the payment, make sure that what happens when the user buys your product actually happens. If it doesn't, then thats going to be an error with your doRemoveAds method. Again, I recommend using changing the background to blue for testing the in-app purchase, this should not be your actual in-app purchase though. If everything works and your good to go! Just make sure to include the in-app purchase in your new binary when you upload it to iTunesConnect! Below are some common errors:

Logged: No Products Available this means that you didn't put in the correct in-app purchase ID, or, you didn't clear it for sale.

If it doesn't work the first time don't get frustrated and give up! It took me about 5 hours straight before I could get this working, and about 10 hours searching for the right code! If you use the code above exactly, it should work fine! Feel free to comment if you have any questions at all

Hope this helps to all of those hoping to add an in-app purchase to their XCode ios application! Cheers!

share|improve this answer
3 
I really appreciated your response, and in fact I voted up both the question and the answer. but i have encountered a problem whit restore purchase. i think that you need to add this line of code [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; in - (IBAction)restore ..What do you think? –  Ilario Jan 11 at 18:52 
1 
@Ilario at the moment, I believe it is fine, I use that restore code in one of my applications and it works. – Jojodmo Jan 11 at 19:52
   
but if i not add that line, when i click on restore button nothing happen.. anyway thank you very much for this tutorial ;) –  Ilario Jan 13 at 8:52
   
I would suggest that you save the settings that the ad has been removed in the keychain. TheNSUserDefault is really easy to edit with some simple knowledge. –  rckoenes Feb 20 at 15:59
   
@rckoenes This is just a simple tutorial to teach people how to implement IAPs, but, thank you for bringing that up. I'll add how to use keychain into the tutorial –  Jojodmo Feb 21 at 3:17
   
@Jojodmo2010 This is a superb tutorial thank you :) It has helped me add in app purchase to my app. Although I do agree with rckoenes that the Keychain should be used instead of NSUserDefault – Supertecnoboff Feb 25 at 15:01
   
@Jojodmo2010 By the way for the if function surely it would make sense to test for this: "areAdsRemoved != 1" because you're if statement just checks if areAdsRemoved exists.... Does it not??? –  Supertecnoboff Feb 25 at 21:05
   
works totally fine for me. @Jojodmo2010 thx you so much for this intro! –  Zero3nna Mar 12 at 13:37
   
@Supertecnoboff actually, areAdsRemoved is a boolean, and doing if(areAdsRemoved) is the same asif(areAdsRemoved == true) –  Jojodmo Mar 12 at 14:09 
4 
Some corrections: after creating the test user account, DO NOT log in to this as you will be glided through the pathway of a normal account, including the requirement of a credit card. Instead, log out of your true account, run the app on your device FROM XCODE WITH IT CONNECTED. When you choose to make your purchase, you will then be prompted to enter account information. NOW enter your test user account information. – Naseiva Khan Mar 16 at 10:04
   
@NaseivaKhan Actually, when you create a test account, you do not need to add any information but your Name, Email, and birth date. Also, running the app without having your phone connected to XCode makes sure that other users will have the correct experience when purchasing. –  Jojodmo Mar 16 at 16:57
1 
I also had to add [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; to the restore method to get this to work. I think if you made a purchase, then restore would work since the delegate was assigned during the purchase. But if you start the app and never purchase, and then restore, there would be no delegate assigned. –  Miebster Mar 17 at 13:38
   
@Jojodmo Actually, I didn't say anything about creating the test account, I spoke of the errors in the answer AFTER the test account is created. –  Naseiva Khan Mar 17 at 14:53
   
@NaseivaKhan Same concept applies. I've never run into any errors using my method, but If you do thanks for informing me! –  Jojodmo Mar 17 at 21:36
   
@jojodmo What NaseivaKhan is talking about is that you've mentioned to 'log-in' with your test account after logging out from the real account. Log-in through System app with test account will lead you to the form that you should add more information such as credit card info or so. And that may void your status of testing purposes as apple Doc says it would. You need to log-out from iTunes and test the app without logging in again. You'll eventually have to type in your test account & password right after tapping the purchase button. – Scha Mar 22 at 4:31
   
@Scha Just like I said in the reply, using the way I described, I never run into any problems –  Jojodmo Mar 31 at 22:05
   
@jojodmo , i am sorry i didn't mean to offend but i am trying to use your tutorial of which i already marked up because i thought you had put a great amount of work in it. I found some confusion when trying to use it because it doubles up the purchase action. –  clive dancey Apr 14 at 22:07
   
@clivedancey What do you mean by your not trying to offend me?... What happens when you try to use this code, where in the code does it happen, and what do you do to get the error? I could probably help you – Jojodmo Apr 14 at 22:09
   
@jojodmo , as you had marked down my answer/comment...anyway i have tried your method but continually get an exception error in selector pointing to the IBAction purchase..if i link the purchase button in storyboard it doesn't link to the Ibaction purchase in the .m file , i then manually link that and it gives me two inactions purchase and purchase: ..which then gives me an exception error , on simulator and on device , I have put in a log statement in the purchase button and it doesn't even get that far..any help would be great , thanks – clive dancey Apr 14 at 22:13
   
@clivedancey You got downvoted because that post did not provide an answer to the question. The reason it wasn't working before is because you have to actually manually link it. This code was written for if you're using a xib file. You could probably add a timer & a BOOL in the purchase action to fix this. on Purchase check if your boolean is true, if it is, set it to false, do the purchase actions, then have a timer go for 1-5 seconds and then set it back to true. –  Jojodmo Apr 14 at 22:19
   
You have no idea how thankful I am for this answer, I've been looking for a good tutorial for ages and this one is perfect! I wish I could give you 100^100 up votes! –  Arbitur Apr 16 at 11:04 
   
I am not using any .Xib or storyboard(I am using cocos2d-x). So how to make restore and purchase button. Now I am doing this through removeads buttons when he click on directly it is asking to buy the product. Can you please tell me how can I do it. –  socrates Nov 5 at 9:37