Detect Cancel Button Tap for "Confirm Your In-App Purchase" UIAlert - iphone

I implemented in-app purchase based on this tutorial. The problem I experience is that I cannot detect when Cancel button is pressed on the "Confirm Your In-App Purchase" alert, which is a part of StoreKit framework.
Some sources suggest -(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions is called when Cancel is pressed but in my case it never runs. My set up is the ViewController which imports IAPManager:NSObject class which conforms to SKProductRequestDelegate and SKPaymentTransactionObserver. Product is successfully being requested but transaction observer is never calling paymentQueue.
How can I make it work so I can detect Cancel button?

in delegate method i look at the tutorial failedtransaction does nothing if user cancels. but you can add it like that.
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
if (transaction.error.code != SKErrorPaymentCancelled)
{
// error!
NSLog(#"Something went Wrong!");
[self finishTransaction:transaction wasSuccessful:NO];
NSLog(#"transaction error :%#", transaction.error.localizedDescription);
}
else
{
NSLog(#"Cancelled");
// this is fine, the user just cancelled
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}

This line had to be added to make it work:
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
Thanks all for your help.

I haven't used StoreKit, but I'm guessing that your SKRequestDelegate will receive the message request:didFailWithError: if the user cancels.

Related

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.

Combine Buy/Restore in app purchase button

in our app I have a purchase button & a restore button however I would like to make it so that instead of 2 seperate buttons I can just use one, which then prompts what to do.
Would anyone be able to assist in editing the code below so that when the user clicks the button, a UIAlert pops up with one button to say Upgrade, one to say Restore, the other Cancel.
Here is the current code used to buy / restore;
-(IBAction) actionRemoveAds
{
[[MKStoreManager sharedManager] buyFeatureA];
}
-(IBAction) actionRestore
{
[MKStoreManager sharedManager];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (alertView.tag==111) {
if (buttonIndex==0) {
[[MKStoreManager sharedManager]buyFeatureA];
}
}
}
Many thanks,
Chris

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 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.

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.