iPhone App : In App Purchase - iphone

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.

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.

in App Purchases iOS

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.

repetition of methods while purchasing

My control reaches to method:
IAPHelper.m
- (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;
}
}
}
after notification method in
viewcontroller.m
- (void)productPurchased:(NSNotification *)notification {
NSLog(#"product purchased notification");
[NSObject cancelPreviousPerformRequestsWithTarget:self];
[MBProgressHUD hideHUDForView:self.navigationController.view animated:YES];
NSString *productIdentifier = (NSString *) notification.object;
NSLog(#"Purchased: %#", productIdentifier);
}
how could i stop this ? any bunch line of code or something else that could stop going at transaction method in IAPHelper.m class after purchasing second product?
Yes, i experienced similar behaviour some time ago. I managed to work around it by keeping track (locally) of already delivered products and i ignore the subsequent callbacks from StoreKit for the delivered products.

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.