Monday, 8 June 2015

In App Purchase in iOS


In App Purchase as the word explain itself that it means purchasing inside the app. In iOS application you can get money with different various methods like – Free ads,paid app and In App purchase. In this tutorial you will get how to use the In App Purchase in your application.

Type of In App Purchase -

  1. Consumable – In this type of In App Purchase you can buy as many times as you want. Ex – Purchasing a life in games
  2. Non-Consumable - In this type of In App Purchase you have to purchase only once and you get product for always. Ex – Unlocking a feature in game
  3. Auto Renewable Subscription – In this types of In App Purchase user can subscribe a product for certain period of time and after subscription period ends up it will automatic renew. Ex – Subscribing a magazine for 3 months
  4. Non Renewable Subscription – This is same as auto renewable subscription having difference that product is not auto renew user have to explicitly renew it.
  5. Free Subscription – In this type of subscription user have not to give any money only he have to subscribe it freely.


From above we have learn about In App Purchase and its types now we will learn how to use it in iOS app.

For using In App Purchase iOS provides StoreKit framework for its implementation.

First step that involve in using In App Purchase is the configuration of it in iTunes connect.

  1. Create your app in iTunes connect.
  1. Click on your app icon that will open the detail shown in below screenshot.Navigate to the InApp purchase section.

  2. Click on create new button and select the type of In App Purchase that you want to implement.
  3. Now enter the Reference name,Product ID,Language,screenshot,review notes and select the price matrix.

  4. Click on save and note the ProductID that you have created. We will use this ProductID in our app to fetch the detail and making payments.




Retrieving Product Information

Before getting product information we have to check that user can make payments or not. If user can not make payments then we will show alert to the user otherwise we will make request for getting product information.

Note – Here in this tutorial we are taking only one product. If you have multiple product then pass all the product Ids in the arrayProducts.

if ([SKPaymentQueue canMakePayments])
{
        NSArray *arrayProducts = [NSArray arrayWithObjects:PRODUCT_ID, nil];
        SKProductsRequest *productsRequest = [[SKProductsRequest alloc                                    initWithProductIdentifiers:[NSSet setWithArray:arrayProducts]];
        productsRequest.delegate = self;
        [productsRequest start];
}else
{
        self.callback([NSDictionary dictionaryWithObjectsAndKeys:@"You are restricted to               purchase.",@"Message",@"0",@"Success",nil]);
}


Create a SKProductsRequest object with product Ids and pass the delegate that conforms its SKProductsRequestDelegate protocol. It will fetch all the details from the iTunes Connect.

Now to get the product details implement SKProductsRequestDelegates.


#pragma mark SKProductRequest Delegates

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
        NSArray *products = response.products;

        if ([products count] > 0)
        {
                BOOL isExists = FALSE;
                for (SKProduct *product in products)
                {
                        NSLog(@" Available %@ - %@ - %@ - %@", product.productIdentifier                                product.localizedTitle, product.localizedDescription, product.price);
                        if ([product.productIdentifier isEqualToString:productIdentifier])
                        {
                                isExists = TRUE;
                                [self purchaseProduct:product];
                                break;
                        }
                }
                if (!isExists)
                {
                        self.callback([NSDictionary dictionaryWithObjectsAndKeys:@"No product                                 available.",@"Message",@"0",@"Success",nil]);
                }
        }
        else
        {
                self.callback([NSDictionary dictionaryWithObjectsAndKeys:@"No product                                 available.",@"Message",@"0",@"Success",nil]);
        }
}


From above delegate we get all the product details. If the product ID we get match with the product ID that we have used then make a call for purchase.

Note - Since here we have pass only one ProductID so detail of only one product will come. If you have multiple product then display all the above product details in a UITableView with a Buy Button on each row. Once user click on buy then call the below method purchaseProduct and pass SKProduct object.


- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
        NSLog(@"Error! %@",error);
        self.callback([NSDictionary                              dictionaryWithObjectsAndKeys:error.localizedDescription,@"Message",@"0",@"Success",nil]);
}

If the product request gets fail then we will get the callback on didFailWithError with the failure reason in error object.

Purchase a Product


For purchasing a product we create a SKPayment object with product object we get in above delegate and add it to SKPaymentQueue. To get the transaction state we add
transaction observer which conforms SKPaymentTransactionObserver protocol. We have only one product so we have called this method in above delegate once we get the product detail.

-(void)purchaseProduct:(SKProduct*)product
{
        if ([SKPaymentQueue canMakePayments])
        {
                SKPayment *payment = [SKPayment paymentWithProduct:product];
                [[SKPaymentQueue defaultQueue] addPayment:payment];
                [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
        }
        else
        {
                self.callback([NSDictionary dictionaryWithObjectsAndKeys:@"You are not authorized to purchase from AppStore.",@"Message",@"0",@"Success",nil]);
        }
}

#pragma mark SKPaymentTransactionObserver

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
        for (SKPaymentTransaction *transaction in transactions)
        {
                switch (transaction.transactionState)
                {
                        case SKPaymentTransactionStatePurchased:
                        {
                                if ([self verifyReceipt])
                                {
                                        [self completeTransaction:transaction];
                                }
                                else
                                        [self failedVerifyReceipt:transaction];
                        }
                        break;
                        case SKPaymentTransactionStateFailed:
                                [self failedTransaction:transaction];
                        break;
                        case SKPaymentTransactionStateRestored:
                                [self restoreTransaction:transaction];     
                        break
;
                        default:
                        break;
                }
        }
}


The above delegate gives the status of the purchase.It gives the status based on whether it is failed,restored or Purchased.

- (
void)completeTransaction:(SKPaymentTransaction *)transaction
{
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        self.callback([NSDictionary dictionaryWithObjectsAndKeys:@"Purchase completed.",@"Message",@"1",@"Success",nil]);
}

- (void)failedVerifyReceipt:(SKPaymentTransaction *)transaction
{
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        self.callback([NSDictionary dictionaryWithObjectsAndKeys:@"Verify receipt failed.",@"Message",@"0",@"Success",nil]);
}

- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
        if (transaction.error.code != SKErrorPaymentCancelled)
        {
                self.callback([NSDictionary dictionaryWithObjectsAndKeys:@"Transaction                             Failed!",@"Message",@"0",@"Success",nil]);
        }
        else
        {
                self.callback([NSDictionary dictionaryWithObjectsAndKeys:@"Transaction                             Cancelled",@"Message",@"0",@"Success",nil]);
        }
        [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}

- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        self.callback([NSDictionary dictionaryWithObjectsAndKeys:@"Transaction restore               successfully.",@"Message",@"1",@"Success",nil]);
}

Depending on the above purchased status finish the transaction observer and inform the user.

For the security point of view and unauthorized access of copies of you application add the verifyReceipt code to get the receipt validated.


- (BOOL)verifyReceipt
{
        NSURL *receiptFileURL = [[NSBundle mainBundle] appStoreReceiptURL];
        NSData *receiptData = [NSData dataWithContentsOfURL:receiptFileURL];
        NSString *recieptString = [receiptData base64EncodedStringWithOptions:kNilOptions];
        NSDictionary *jsonDict = [NSDictionary                      dictionaryWithObjectsAndKeys:recieptString,@"receipt-                  data",@"827d5be5c5944b3db18bbb0278c3e8bd",@"password", nil];
        NSError *error;
        NSData *requestData = [NSJSONSerialization dataWithJSONObject:jsonDict
        options:error:&error];
        if (requestData)
        {
                //NSURL *url =[NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"];
                NSURL *url = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
                NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
                [request setHTTPMethod:@"POST"];
                [request setValue:@"application/json" forHTTPHeaderField:@"Accept"];
                [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
                [request setValue:[NSString stringWithFormat:@"%lu", (unsigned long)                                  [requestData length]] forHTTPHeaderField:@"Content-Length"];
                [request setHTTPBody:requestData];
                NSURLResponse *response;
                NSData* result = [NSURLConnection sendSynchronousRequest:request                               returningResponse:&response error:&error];
                NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:&error];
                if(jsonResponse)
                {
                        int status = [[jsonResponse objectForKey:@"status"] intValue];
                        if(status == 0)
                        {
                               NSDictionary *dicReceipt = [jsonResponse objectForKey:@"receipt"];
                                   NSLog(@"Receipt Information - %@ ", dicReceipt);
                                return YES;
                        }
                        else
                                return NO;
                 }
                else
                        return NO;
        }
        else
                return NO;
}

Note – Don't forgot to comment sandbox url while submitting your app.

This was all for implementing In App Purchase in your application. But wait there is one more important thing left that your application should include.


Restoring Transactions


This is provided to restore transaction when user switch to another device and want to get its purchase back on new device. Provide a button on your UI to get user restore there In App Purchase.

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

Testing your In App Purchase - 
To test your application in sandbox mode create a sandbox tester account in iTunes connect.

1) Login to iTunes

2) Select User and Roles

3) Select the Sandbox Tester tab and add a test account to test your In App Purchase.

That was all for In App Purchase. Keep enjoying to add it and get paid. :)

Here is sample project with all the code of the above tutorial. Pass your product ID in tutorial to test your In App Purchase. Use InAppPurcahseHelper class to easily integrate In App Purchase on your code.

If you face any issue,leave your comment. 

5 comments:

  1. I would be appreciated if you answer this question.

    https://github.com/pradeep7may/InAppPurchase/issues/1

    ReplyDelete
  2. You can get app to give money and some apps are free. Modifying Metal Designs You can give money as rent and you can buy permanently. Get new options in apps.

    ReplyDelete