Powered By Blogger

Tuesday, August 28, 2012

In-App Purchase Tutorial in iPhone

Hi,
Everyone, 
Here, I'm going to start the explanation for In-App Purchase for non-consumable product in iPhone/iPad. 

 You have to follow the below steps before you implement the code given below:


 After Creating new APP Id and making In-App Purchase Enabled , You have to create product identifier for non-consumable purchase and need to fill all required information .

After completion all process to itunesconnect.apple.com, you can implement the below code into you project file.

#import <StoreKit/StoreKit.h>
#define kMyFeatureIdentifier @"" //Product Identifier in In-App Purchase

@interface AppDelegate : UIResponder <UIApplicationDelegate,SKPaymentTransactionObserver ,SKRequestDelegate, SKProductsRequestDelegate>
{
    NSArray *arrPurchaseProducts;
    SKProduct *product;
}



#import "AppDelegate.h"

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    if([SKPaymentQueue canMakePayments])
    {
        if (![[NSUserDefaults standardUserDefaults] valueForKey:@"isPurchased"])
        {
            // restarts any purchases if they were interrupted last time the app was open
            [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
            [self requestProductData];
        }
        NSLog(@"IN-APP:can make payments");
    }
    else {
        NSLog(@"IN-APP:can't make payments");
    }
}
   

#pragma mark -
#pragma User-Defined Method for Restore product functionality

-(void)checkPurchasedItems
{
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}

#pragma mark -
#pragma mark In-App Purchase Delegate Methods

- (void)requestProductData
{

    NSLog(@"IN-APP:requestProductData");
    SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kMyFeatureIdentifier]];
    request.delegate = self;
    [request start];
    NSLog(@"IN-APP:requestProductData END"); 
}

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    NSLog(@"IN-APP:productsRequest");
    NSArray *myProduct = [[NSArray alloc]initWithArray:response.products];
    if ([myProduct count]>0)
    {
        SKProduct *product = [myProduct objectAtIndex:0];
        NSLog(@"Price: %.2f",product.price.floatValue);
        NSLog(@"Price Locale: %@",product.priceLocale.localeIdentifier);
        NSLog(@"Product Identifier: %@",product.productIdentifier);
        NSLog(@"IN-APP:array count: %i", [myProduct count]);
        [request autorelease];
        NSLog(@"IN-APP:productsRequest END");
    }
    [myProduct release];
    myProduct = nil;
}

-(void)buyProduct
{
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:kMyFeatureIdentifier];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    payment = nil;
//    if (arrPurchaseProducts.count>0)
//    {
//        SKProduct *selectedProduct = [arrPurchaseProducts objectAtIndex:0];
//        SKPayment *payment = [SKPayment paymentWithProduct:selectedProduct];
//        [[SKPaymentQueue defaultQueue] addPayment:payment];
//        selectedProduct = nil;
//        payment = nil;
//    }
}

#pragma mark -
#pragma mark SKPaymentTransactionObserver methods

// called when the transaction status is updated
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
                break;
            case SKPaymentTransactionStatePurchasing:
                NSLog(@"Purchasing...");
                break;
            default:
                break;
        }
    }
}


#pragma -
#pragma Purchase helpers

// saves a record of the transaction by storing the receipt to disk
- (void)recordTransaction:(SKPaymentTransaction *)transaction
{
    if ([transaction.payment.productIdentifier isEqualToString:kMyFeatureIdentifier])
    {
        // save the transaction receipt to disk
        [[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"proUpgradeTransactionReceipt"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}

// enable pro features
- (void)provideContent:(NSString *)productId
{
    if ([productId isEqualToString:kMyFeatureIdentifier])
    {
        // enable the pro features
        [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"isPurchased"];
        [[NSUserDefaults standardUserDefaults] synchronize];
    }
}


// removes the transaction from the queue and posts a notification with the transaction result
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
    // remove the transaction from the payment queue.
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil];
    if (wasSuccessful)
    {
        // send out a notification that we’ve finished the transaction
        [[NSNotificationCenter defaultCenter] postNotificationName:@"PurchaseSuccess" object:self userInfo:userInfo];
    }
    else
    {
        // send out a notification for the failed transaction
       // [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];
    }
}

// called when the transaction was successful
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    [self recordTransaction:transaction];
    [self provideContent:transaction.payment.productIdentifier];
    [self finishTransaction:transaction wasSuccessful:YES];
}

// called when a transaction has been restored and and successfully completed
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
    [self recordTransaction:transaction.originalTransaction];
    [self provideContent:transaction.originalTransaction.payment.productIdentifier];
    [self finishTransaction:transaction wasSuccessful:YES];
}

// called when a transaction has failed
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        // error!
        [self finishTransaction:transaction wasSuccessful:NO];
        if (transaction.error.code == SKErrorClientInvalid) {
            [self showAlert:@"In-App Purchase" withMessage:INVALID_CLIENT];
        }
        else if (transaction.error.code == SKErrorPaymentInvalid) {
            [self showAlert:@"In-App Purchase" withMessage:PAYMENT_INVALID];
        }
        else if (transaction.error.code == SKErrorPaymentNotAllowed) {
            [self showAlert:@"In-App Purchase" withMessage:PAYMENT_NOT_ALLOWED];
        }
        else if (transaction.error.code == SKErrorPaymentCancelled) {
           // [self showAlert:@"In-App Purchase" withMessage:@"This device is not allowed to make the payment."];
            NSLog(@"User Cancellation.");
        }
        else {
           // SKErrorUnknown
            NSLog(@"Unknown Reason.");
        }
    }
    else  {
        // this is fine, the user just cancelled, so don’t notify
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    }
}

//Then this delegate Funtion Will be fired
- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
    NSLog(@"received restored transactions: %i", queue.transactions.count);
    for (SKPaymentTransaction *transaction in queue.transactions)
    {
        NSString *productID = transaction.payment.productIdentifier;
    }
   
}

5 comments:

  1. The productsRequest method should be change to this : , your code did not work until I change it :

    - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
    {
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

    NSArray *myProduct = response.products;
    NSLog(@"%@",[[myProduct objectAtIndex:0] productIdentifier]);

    //Since only one product, we do not need to choose from the array. Proceed directly to payment.

    SKPayment *newPayment = [SKPayment paymentWithProduct:[myProduct objectAtIndex:0]];
    [[SKPaymentQueue defaultQueue] addPayment:newPayment];
    }

    ReplyDelete
    Replies
    1. Yes.. you have to do that in case of purchasing multiple products.

      Thanks,
      Nilesh M. Prajapati

      Delete
  2. Hi Nilesh Can U send sample the in app purchase to the below mail id really i get confused while reading this

    cprithivimca@gmail.com

    ReplyDelete
  3. Hi,
    Sorry but this is what you can see. I can't send mail to everyone personally and please try to understand my problem. I'm not able to send each and everybody who want such kind of code for different functionalities. Please read the steps carefully and follow those same.

    Regards,
    Nilesh M. Prajapati

    ReplyDelete