Thursday, 3 April 2014

In App Purchase implementation with receipt validation from iTunes through Objective - C

To implement In App Purchase we need to look around many things as follows:

1) First of all create a test account steps:

Go for     https://itunesconnect.apple.com

Enter login credentials and click on Manage users tab see below image for reference



Then click on Test user and create test account.

2) Go for Manage Your Apps and select your app click on Manage In - App Purchases.
and create a in app purchase by filling out details.

3) Now come to your Xcode create a new file and paste below code in .h file

---------------------------------------Start------------------------------------------
#import <Foundation/Foundation.h>

@protocol InAppPurchaseHandlerDelegate <NSObject>

-(void)inAppPurchaseHandlerReturnReciept:(NSData*)receipt otherResponse:(NSString*)dataResponse;

@end

@interface InAppPurchaseHandler : NSObject


+(InAppPurchaseHandler*)sharedInstance;

@property id <InAppPurchaseHandlerDelegate> delegate;


-(void)requestProduct:(NSString*)productIdentifier;
@end

----------------------------------------End-----------------------------------------

Now paste below code in your .m file

------------------------------------Start---------------------------------------------


#import "InAppPurchaseHandler.h"
#import <StoreKit/StoreKit.h>



@interface InAppPurchaseHandler ()<SKProductsRequestDelegate,SKPaymentTransactionObserver>

@property SKProductsRequest * productRequest;
@end

@implementation InAppPurchaseHandler


static InAppPurchaseHandler * sharedObject;


+(InAppPurchaseHandler*)sharedInstance{ 
    @synchronized(self){
        if (sharedObject==nil) {
            sharedObject=[[InAppPurchaseHandler alloc]init];
        }
    }
    return sharedObject;
}




-(void)requestProduct:(NSString*)productIdentifier{

    _productRequest= [[SKProductsRequest alloc] initWithProductIdentifiers:   [NSSet setWithObject: productIdentifier]];
    _productRequest.delegate = self;
    [_productRequest start];
}
#pragma mark - SKProductsRequestDelegate
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
    
    int coutProduct=[response.products count];
    
    if (coutProduct>0) {
        SKProduct * product = [response.products lastObject];

        NSLog(@"%@",[NSString stringWithFormat:@"Product Title: %@",product.localizedTitle]);
         NSLog(@"%@",[NSString stringWithFormat:@"Product Description: %@",product.localizedDescription]);
         NSLog(@"%@",[NSString stringWithFormat:@"Product ProductIdentifier: %@",product.productIdentifier]);
        [self makePayementForProduct:product];
    }  else{
        NSLog(@"Product not available!");
    }
    
}

-(void)request:(SKRequest *)request didFailWithError:(NSError *)SKRequest{
     NSLog(@"%@",[NSString stringWithFormat:@"SKRequest SKRequest: %@",SKRequest.localizedDescription]);
  
    NSString* transactionState =[NSString stringWithFormat:@"%@",SKRequest.localizedDescription];
    [self.delegate inAppPurchaseHandlerReturnReciept:nil otherResponse:transactionState];
}



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





-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    
    
    NSData * transactionReceipt=nil;
    
    for (SKPaymentTransaction * transaction in transactions) {
        
        
        
        switch (transaction.transactionState) {
                
            case SKPaymentTransactionStatePurchasing:
                transactionReceipt=transaction.transactionReceipt;
                NSLog(@"%@ transactionReceipt %@",transaction.transactionReceipt,transactionReceipt);
                break;
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
            default:
            break;        }
        
        
        
    }

}
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
    NSLog(@"completeTransaction...");

    NSString *base64TxReceiptStr = [self base64forData:transaction.transactionReceipt];

    NSDictionary *command = [NSDictionary dictionaryWithObjectsAndKeys:
                             base64TxReceiptStr, @"receipt-data",
                             nil];
    
    NSData* encodedData = [NSJSONSerialization dataWithJSONObject:command options:NSJSONWritingPrettyPrinted error:nil];
    
    [self.delegate inAppPurchaseHandlerReturnReciept:encodedData otherResponse:nil];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
    
    
}
- (NSString*) base64forData:(NSData*)data {
    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    
    const int size = ((data.length + 2)/3)*4;
    uint8_t output[size];
    
    const uint8_t* input = (const uint8_t*)[data bytes];
    for (int i = 0; i < data.length; i += 3)
    {
        int value = 0;
        for (int j = i; j < (i + 3); j++)
        {
            value <<= 8;
            if (j < data.length)
                value |= (0xFF & input[j]);
        }
        
        const int index = (i / 3) * 4;
        output[index + 0] =  table[(value >> 18) & 0x3F];
        output[index + 1] =  table[(value >> 12) & 0x3F];
        output[index + 2] = (i + 1) < data.length ? table[(value >> 6)  & 0x3F] : '=';
        output[index + 3] = (i + 2) < data.length ? table[(value >> 0)  & 0x3F] : '=';
    }
    
    return  [[NSString alloc] initWithBytes:output length:size encoding:NSASCIIStringEncoding];
}

- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
    NSLog(@"restoreTransaction...");
    
   
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

- (void)failedTransaction:(SKPaymentTransaction *)transaction {
    
    NSLog(@"failedTransaction...");
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
    }
    
    NSString* transactionState =@"failed";
    [self.delegate inAppPurchaseHandlerReturnReciept:nil otherResponse:transactionState];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}




-(void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue{
    
    
    
}
@end

-------------------------------------End--------------------------------------------


4) Now include above class to your class where you are want to perform this action as follows call belw method named inappHit :

-(void)inappHit:(UIButton*)sender
{
    // i am using 105 as a product key change it as required

    NSString *productIdentifier=[NSString stringWithFormat:@"105"];
    [InAppPurchaseHandler sharedInstance].delegate=self;
    [[InAppPurchaseHandler sharedInstance]requestProduct:productIdentifier];
}

// delegate function
-(void)inAppPurchaseHandlerReturnReciept:(NSData *)receipt otherResponse:(NSString *)dataResponse
{
    //receipt    
    NSLog(@"receipt %@",receipt);
    
    if ([[NSString stringWithFormat:@"%@",receipt] isEqualToString:@"(null)"])
    {
    [alert_itunes_connecting dismissWithClickedButtonIndex:0 animated:YES];
       alert_itunes_connecting= [[UIAlertView alloc]initWithTitle:dataResponse message:nil delegate:self cancelButtonTitle:@"ok" otherButtonTitles:nil  , nil];
        [alert_itunes_connecting show];
    }else
    {
       [self hitLocalServerReceipt:receipt];
    }
}


//  itunes hit for receipt validation
-(void)hitLocalServerReceipt:(NSData *)receiptString
{

// NOTE: use "buy" vs "sandbox" in production.


    NSMutableURLRequest *txReceiptVerificationRequest=[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"]];
    [txReceiptVerificationRequest setHTTPBody:receiptString];
    [txReceiptVerificationRequest setHTTPMethod:@"POST"];
    
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:txReceiptVerificationRequest];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        NSError *e = nil;
        NSArray* array= [NSJSONSerialization JSONObjectWithData:responseObject options: NSJSONReadingMutableContainers error: &e];
        NSLog(@"response from iTunes%@",array); // your response
        
    } failure:^(AFHTTPRequestOperation *operation, NSError *error)
     {
         NSLog(@"ERROR : %@",error);
         
     }];
    [operation start];
}