in App Purchases iOS - iphone

I made my first app with IAP by
this tutorial
I made a singleton for InAppPurchaseManager, added 3 more purchases, methods for them and all works great. The problem is what my app is a gallery where user have 9 items free and after them 18 items paid. How can I check in my ViewController if purchase successfully made exactly when system UIAletrView is showing? Or maybe I can retrieve this alert in my ViewController?
For gallery I'm using UICollectionView, if purchase done I need reload it

You can check the status of the transaction by using this delegate method..
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
NSLog(#"%i",[transaction transactionState]);
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
// [self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
// [self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
// [self restoreTransaction:transaction];
case SKPaymentTransactionStatePurchasing: {
// if([self.delegate respondsToSelector:#selector(inProcessPurchasingTransaction)])
// [self.delegate inProcessPurchasingTransaction];
}
default:
break;
}
}
}
And the following delegate method will fire when the transaction success :
- (void) completeTransaction: (SKPaymentTransaction *)transaction
And in case of fail :
- (void) failedTransaction:(SKPaymentTransaction *)transaction
And for a testing purpose you need 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.

Related

displaying dialogue after in-app purchase complete

I have implemented the SKPaymentTransactionObserver in my apps AppDelegate the way Apple recommended:
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
if (transaction.error.code != SKErrorPaymentCancelled)
{
// Optionally, display an error here.
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
self.products = response.products;
}
- (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];
default:
break;
}
}
}
I'd like for my app to send a dialogue message to the user when the following happens: purchase successful, purchase failed, restore successful, restore failed. I'm having a little trouble wrapping my head around how I can do this with my design set up. I have a couple of questions:
1) The alert needs to be posted in the view controller where the transaction is initialized. How can I make the AppDelegate communicate with this view controller to let it know when an event has happened? Do I set up a delegate for the AppDelegate? This seems kind of funny to me...is there a better way?
2) Where do I send the message? Should it be in finishTransaction (do I need to override?) or somewhere else?
Passing a notification will be the best way for it. The view controller which invokes the payment procedure should register for notification.
On the completion of a transaction, app delegate will post the notification which controller will receive and it will show the appropriate message.

In consumable InAppPurchase, delegate of cancel transaction not found in ios5.1 but found in ios 6.1

On confirm your In-App Purchase, I am cancelling the purchase.
In iOS 6.1 after cancel, control transfered to - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions method.
In iOS 5.1, no any delegate method will get called. So I am not able to control app on cancelling TRANSACTION.
My code to buy product:
- (void)buyProduct:(SKProduct *)product
{
NSLog(#"Buying %#...", product.productIdentifier);
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
Delegate Method:
#pragma mark SKPaymentTransactionOBserver
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
NSLog(#"updated 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];
case SKPaymentTransactionStatePurchasing:
NSLog(#"SKPaymentTransactionStatePurchasing");
break;
default:
break;
}
};
}
Please let me know what is the issue.
I found the solution. It was working in both iOS in device. The Problem is of validate receipt. If you are testing inApp purchase using test user then you need to use sandbox verify receipt that is
#define TMS_SANDBOX_VERIFY_RECEIPT_URL #"https://sandbox.itunes.apple.com/verifyReceipt". but when you are uploading app to the appstore then you need to change it to
#define ITMS_PROD_VERIFY_RECEIPT_URL  #"https://buy.itunes.apple.com/verifyReceipt".
So when user download the app from the app store then for the valid receipt verification 'ITMS_PROD_VERIFY_RECEIPT_URL' is must. otherwise it will give failed receipt verification.
So please use #define ITMS_PROD_VERIFY_RECEIPT_URL #"https://buy.itunes.apple.com/verifyReceipt" when you are uploading app to the app store.

How do I stop a loading indicator when In-App-Purchase window pops up on iPhone?

When user tap the purchase a product button, i wanna show loading indicator before
In-App-Purchase window pops up.
But i don't know which delegate method i stop the indicator.
you could possible show it when you add the payment to SKPaymentque
SKPayment *newPayment = [SKPayment paymentWithProduct:aPakage.storeProduct];
[[SKPaymentQueue defaultQueue] addPayment:newPayment];
For removing you could implement a method for
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
[transactionsArray addObjectsFromArray:transactions];
for (SKPaymentTransaction *currentTransaction in transactions) {
switch (currentTransaction.transactionState) {
case SKPaymentTransactionStatePurchasing: {
break;
}
case SKPaymentTransactionStatePurchased: {
[self completeTransaction:currentTransaction];
break;
}
case SKPaymentTransactionStateFailed: {
[self failedTransaction:currentTransaction];
break;
}
default:
break;
}
}
}
you can remove your loading screen when this delegate method is called according to state of the purchase.Me personally implemented two separate functions for failed and succeeded transactions.

iPhone App : In App Purchase

In iPhone App for in App Purchase: when is SKPaymentTransactionStateRestored: called?
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStateRestored:
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
}
}
}
And how to get confirmation from apple that the app is purchased successfully means I want to Print that information in NSlog.
what should I write for that?
As far as i'm concerned, transactions is purchased successfully only if Apple responses the updatedTransactions state as SKPaymentTransactionStateRestored or SKPaymentTransactionStatePurchased.
When the method:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for (SKPaymentTransaction * transaction in transactions) {
//process the transaction
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
break;
default:
break;
}
}
}
is called it means that you have finished your transaction with apple and you handle three cases:
SKPaymentTransactionStatePurchased: it means that your product was bought.
SKPaymentTransactionStateFailed: your product couldn't be bought.
SKPaymentTransactionStatePurchased: This is your question. As long as your SKPaymentTransactionObserver is alive the transaction is persistant, meaning that if your client intended to buy you product but something wrong happened while delivering the product (server error or something else), when the app starts again the transaction will return to this method to finish the purchase.
I hope the info helps.

Problems with iPhone SDK StoreKit

In my iPhone app Im using StoreKit to make it possible for users to buy subscriptions in the app. The problem I'm having is that suddenly everytime I start the app SKPaymentTransactionStatePurchased is sent to the observer so the app tries to buy the subscription again and again. And if I try to buy the subscription again from the list of subscriptions in the app I get a message saying "You've already purchased this In App Purchase but it hasn't been downloaded." then failedTransaction is called with SKErrorPaymentCancelled.
EDIT: I have now found a lot of threads about this in the Apple Developer Forum, for example: https://devforums.apple.com/thread/73818 and /thread/73572, it seems like a lot of developers have the same problem..
This is the code I'm using, can you see something wrong with it?
-(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];
default:
break;
}
}
}
-(void) failedTransaction: (SKPaymentTransaction *)transaction
{
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Error");
} else {
NSLog(#"Cancel");
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
-(void) restoreTransaction: (SKPaymentTransaction *)transaction
{
[self subscribe:transaction];
}
-(void) completeTransaction: (SKPaymentTransaction *)transaction
{
[self subscribe:transaction];
}
-(void)subscribe: (SKPaymentTransaction*)transaction {
NSInteger errorCode = //Connects to my server that verifies receipt with Apple server etc..
if (errorCode==0) {
[self provideContent];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
I had the exact problem when using the StoreKit the first time and it happened because as I was implemented the code I was leaving transactions unfinished.
So, when you start the app, you'll need to loop through the queue and finish all transactions. You shouldn't need to do this is you cover all outcomes (which, based on the code above, you did).
After talking to Apple support I was able to solve this issue. It seems to be a problem from Apple that has now been fixed.