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

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.

Related

Get list of purchased products, inApp Purchase iPhone

I am implementing in app purchases for my iOS application. Apple has rejected my binary for not restoring purchased products. In my application once the user taps the icon of product if item is locked he/she directed to inApp purchase process else the products gets openend. There is no visual Buy button. Now apple is saying to provide the restore button? Can anybody tell me how to handle this? I have tried
- (void) checkPurchasedItems
{
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}// Call This Function
//Then this delegate Function Will be fired
- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
alreadyPurchasedItems = [[NSMutableArray alloc] init];
NSLog(#"received restored transactions: %i", queue.transactions.count);
for (SKPaymentTransaction *transaction in queue.transactions)
{
NSString *ID = transaction.payment.productIdentifier;
[alreadyPurchasedItems addObject:ID];
}
}
On application launch but paymentQueueRestoreCompletedTransactionsFinished method is never called so that I can get the list of already purchased items and then directly inform user if he/she purchased this already.
How do you set the delegate of [SKPaymentQueue defaultQueue]? I guess you already do smt like:
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
After that [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; should result in below method to be fired. So the case SKPaymentTransactionStateRestored is where you implement it:
-(void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction * transaction in transactions) {
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
...
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
...
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
...
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
default:
break;
}
};
}
You may have a look at this tutorial, restoration is explained in more detail towards the very end of it.
http://www.raywenderlich.com/21081/introduction-to-in-app-purchases-in-ios-6-tutorial

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.

In App Purchase sandbox not prompting for my login/pass

We're developing an app which (ofcourse) uses in app purchases (IAP).
I've done everything in the guide to enable iap and everything works fine, untill I want to make purchase.
Some of the code:
MainViewController.m
-(void)viewDidLoad {
if ([SKPaymentQueue canMakePayments]) {
MyStoreObserver *observer = [[MyStoreObserver alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObjects: #"com.company.app.product1", #"com.company.app.product1", nil]];
request.delegate = self;
[request start];
}
};
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
for (SKProduct *prod in response.products) {
NSLog(#"%# (%#)", prod.localizedTitle, prod.price);
}
[request release];
};
-(IBAction)clickBuy:(UIButton *)__sender {
SKPayment *payment = [SKPayment paymentWithProductIdentifier:#"com.company.app.product1"];
[[SKPaymentQueue defaultQueue] addPayment:payment];
};
MyStoreObserver.m
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
NSLog(#"SKPaymentTransactionStatePurchased");
break;
case SKPaymentTransactionStateFailed:
NSLog(#"SKPaymentTransactionStateFailed");
break;
case SKPaymentTransactionStateRestored:
NSLog(#"SKPaymentTransactionStateRestored");
break;
case SKPaymentTransactionStatePurchasing:
NSLog(#"SKPaymentTransactionStatePurchasing");
default:
break;
}
}
};
The productRequest: delegate method shows 2 products with their name / price. Like I entered in the iTunes connect site.
But once I click the 'buy' button, no dialog pops up or asks me for my credentials. Only "SKPaymentTransactionStatePurchasing" is logged.
And I:
- ... have logged out in the settings/store pane
- ... am using the right provisioning profiles
- ... am desperate
Anyone?
I encountered a similar problem, but mine was more of a boneheaded move on my part. I had 'refactored' the call to finishTransaction so that it was being called for every state in transactionState:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
// do stuff
break;
case SKPaymentTransactionStateFailed:
// do stuff
break;
case SKPaymentTransactionStateRestored:
// do stuff
break;
default:
break;
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}
Turns out™, this will also call finishTransaction on SKPaymentTransactionStatePurchasing, which will cause a crash. Moving finishTransaction back into each case of the switch statement fixed that.
After Pulling my hair out in frustration with a similar problem (instead of not being asked for my credentials it was automatically filling in the email address without the option to change it even when logged out of the store in the settings app). I discovered that I had a failed transaction stuck in the queue from development builds on the same device, I had to clear all of the transactions in the queue on the device and then try to test again.
NSArray *transactions = [[SKPaymentQueue defaultQueue] transactions];
for(id transaction in transactions){
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
I hooked this code upto an IBOutlet and after being run once my in app purchases worked.
I also had been pulling my hair out a bit with this. Turns out a simple reboot of the test device got everything working fine.
An iPhone can be restricted from accessing the Apple App Store. For example, parents can restrict their children’s ability to purchase additional content.
Before placing transaction make sure, can you u buy or not?Check it like this -
-(IBAction)clickBuy:(UIButton *)__sender {
if ([SKPaymentQueue canMakePayments]) {
SKPayment *payment = [SKPayment paymentWithProductIdentifier:#"Product_id"];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else {
//show appropriate message
}
}
Are you testing on iPhone/iPad Simulator 4.2 or something? That might be the problem. Testing on iPhone/iPad Simulator 5.0, or the device, will run storekit correctly.

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.