In-App Purchase failed transactions - iphone

I use in-app purchases in my application, exactly consumable. But when everything goes fine before I test it. When I enter test user ID and password it goes into the SKPaymentTransactionStateFailed.
Here is some code I use:
- (void) funcPrepareForPurchasing:(NSString *)stringType
{
if([SKPaymentQueue canMakePayments])
{
NSLog(#"Parental Controls are disabled");
SKProductsRequest *pr = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:[NSString stringWithFormat:#"com.Company.AppName.%#", stringType]]];
pr.delegate = self;
[pr start];
}
else
{
UIAlertView *alertviewPR = [[UIAlertView alloc] initWithTitle:#"Parental Controls" message:#"Parental Controls are On" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:NO, nil];
[alertviewPR show];
}
}
- (void) funcPurchaseBonusScores
{
SKPayment *payment = [SKPayment paymentWithProductIdentifier:#"com.Company.AppName.BonusScores"];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void) funcPurchaseBonusLife
{
SKPayment *payment = [SKPayment paymentWithProductIdentifier:#"om.Company.AppName.BonusLife"];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void) funcPurchaseBonusStar
{
SKPayment *payment = [SKPayment paymentWithProductIdentifier:#"com.Company.AppName.BonusStar2"];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
SKProduct *vp = nil;
int count = [response.products count];
NSLog(#"%i", count);
if(count)
vp = [response.products objectAtIndex:0];
else if(!vp)
NSLog(#"No Prodacts are available");
}
- (void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for(SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchasing:
NSLog(#"yidulobs = purchasing");
break;
case SKPaymentTransactionStatePurchased:
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
userDefaultsInApps = [NSUserDefaults standardUserDefaults];
if( intInApps == 1 )
[userDefaultsInApps setInteger:5 forKey:#"keyScores"];
else if( intInApps == 2 )
[userDefaultsInApps setInteger:5 forKey:#"keyLife"];
else if( intInApps == 3 )
[userDefaultsInApps setInteger:5 forKey:#"keyStar"];
[userDefaultsInApps synchronize];
NSLog(#"gadaixada");
break;
case SKPaymentTransactionStateRestored:
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(#"Error an Cancelled!!!");
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
}
}
}
Then I try to purchase with this function:
- (void) func1
{
intInApps = 1;
[self funcPrepareForPurchasing:#"BonusScores"];
[self funcPurchaseBonusScores];
}
- (void) func2
{
intInApps = 2;
[self funcPrepareForPurchasing:#"BonusLife"];
[self funcPurchaseBonusLife];
}
- (void) func3
{
intInApps = 3;
[self funcPrepareForPurchasing:#"BonusStar2"];
[self funcPurchaseBonusStar];
}
What mistake have I done?

I was testing it on the simulator. In-apps doesn't work on it. It's necessary to test it on a device.

Related

How to get check if a product is already purchased using in app purchase in iOS?

I have an application with in app integration in it. In my app I have two buttons for paid app buy and subscribe. When the user clicks on buy it goes check for apple validation and the buy the product.
This works properly but when the product is purchased my buy button should change to 'done' and when the application is next time run the buy button should not be visible for that particular product. Instead 'done' button should be shown. My problem is when a product is purchased the buy button is shown instead of done button.
This is my code:
-(void)checkPurchasedItems
{
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
//Then this delegate Function Will be fired
- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
NSLog(#"received restored transactions: %i", queue.transactions.count);
for (SKPaymentTransaction *transaction in queue.transactions)
{
NSString *productID = transaction.payment.productIdentifier;
NSLog(#"%#",productID);
}
}
// called when a transaction has failed
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
if (transaction.error.code != SKErrorPaymentCancelled)
{
// error!
[self finishTransaction:transaction wasSuccessful:NO];
if (transaction.error.code == SKErrorClientInvalid) {
//[self showAlert:#"In-App Purchase" withMessage:INVALID_CLIENT];
}
else if (transaction.error.code == SKErrorPaymentInvalid) {
//[self showAlert:#"In-App Purchase" withMessage:PAYMENT_INVALID];
}
else if (transaction.error.code == SKErrorPaymentNotAllowed) {
//[self showAlert:#"In-App Purchase" withMessage:PAYMENT_NOT_ALLOWED];
}
else if (transaction.error.code == SKErrorPaymentCancelled) {
// [self showAlert:#"In-App Purchase" withMessage:#"This device is not allowed to make the payment."];
NSLog(#"User Cancellation.");
}
else {
// SKErrorUnknown
NSLog(#"Unknown Reason.");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Transaction Status" message:#"Transaction Failed due to unknown reason" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
}
}
else {
// this is fine, the user just cancelled, so don’t notify
// UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Transaction Status" message:#"Transaction failed due to some reason" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
// [alert show];
// return;
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}
- (void)provideContent:(NSString *)productId
{
if ([productId isEqualToString:kMyFeatureIdentifier4])
{
// enable the pro features
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"isStorePurchased"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
else if([productId isEqualToString:kMyFeatureIdentifier3])
{
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:#"isStoreSubscribed"];
[[NSUserDefaults standardUserDefaults]synchronize];
}
}
- (void)recordTransaction:(SKPaymentTransaction *)transaction
{
NSData *receiptData = [NSData dataWithData:transaction.transactionReceipt];
transactionreceipt = [Base64 encode:receiptData];
NSLog(#"encoded String :%#",transactionreceipt);
if ([transaction.payment.productIdentifier isEqualToString:kMyFeatureIdentifier4])
{
// save the transaction receipt to disk
[[NSUserDefaults standardUserDefaults] setValue:transactionreceipt forKey:#"proUpgradeTransactionReceipt"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
if ([transaction.payment.productIdentifier isEqualToString:kMyFeatureIdentifier3])
{
[[NSUserDefaults standardUserDefaults] setValue:transactionreceipt forKey:#"proUpgradeTransactionReceipt"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
NSUserDefaults *userdefaults = [NSUserDefaults standardUserDefaults];
transactionreceipt = [userdefaults valueForKey:#"proUpgradeTransactionReceipt"];
NSLog(#"%#",transactionreceipt);
// remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, #"transaction" , nil];
if (wasSuccessful)
{
// send out a notification that we’ve finished the transaction
[self sendRequest];
[[NSNotificationCenter defaultCenter] postNotificationName:#"PurchaseSuccess" object:self userInfo:userInfo];
[easytblView reloadData];
}
else
{
// send out a notification for the failed transaction
// [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];
}
}
- (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];
break;
case SKPaymentTransactionStatePurchasing:
NSLog(#"Purchasing...");
break;
default:
break;
}
}
}
// called when a transaction has been restored and and successfully completed
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
[self recordTransaction:transaction.originalTransaction];
[self provideContent:transaction.originalTransaction.payment.productIdentifier];
[self finishTransaction:transaction wasSuccessful:YES];
}
// called when the transaction was successful
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
[self recordTransaction:transaction];
[self provideContent:transaction.payment.productIdentifier];
[self finishTransaction:transaction wasSuccessful:YES];
}
-(void)buyProduct
{
if (arrPurchaseProducts.count>0)
{
SKProduct *selectedProduct = [arrPurchaseProducts objectAtIndex:0];
SKPayment *payment = [SKPayment paymentWithProduct:selectedProduct];
[[SKPaymentQueue defaultQueue] addPayment:payment];
//selectedProduct = nil;
// payment = nil;
}
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSLog(#"IN-APP:productsRequest");
arrPurchaseProducts = [[NSArray alloc]initWithArray:response.products];
if ([arrPurchaseProducts count] == 1)
{
SKProduct *selectedProduct = [arrPurchaseProducts objectAtIndex:0];
SKPayment *payment = [SKPayment paymentWithProduct:selectedProduct];
[[SKPaymentQueue defaultQueue] addPayment:payment];
//responseStatus = 1;
// if ([purchaseButton.title isEqualToString:#" "])
// {
NSLog(#"Purchase had been attempted already.");
// }
}
if ([arrPurchaseProducts count]>0)
{
product = [arrPurchaseProducts objectAtIndex:0];
NSLog(#"Price: %.2f",product.price.floatValue);
NSLog(#"Price Locale: %#",product.priceLocale.localeIdentifier);
NSLog(#"Product Identifier: %#",product.productIdentifier);
NSLog(#"IN-APP:array count: %i", [arrPurchaseProducts count]);
[request autorelease];
NSLog(#"IN-APP:productsRequest END");
}
//[arrPurchaseProducts release];
// arrPurchaseProducts = nil;
}
- (void)requestProductData
{
NSLog(#"IN-APP:requestProductData");
SKProductsRequest *request;
if (isSubscribe==YES)
{
request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kMyFeatureIdentifier3]];
}
else{
request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kMyFeatureIdentifier3]];
}
request.delegate = self;
[request start];
NSLog(#"IN-APP:requestProductData END");
}
-(IBAction)buynow:(id)sender
{
isSubscribe=NO;
isviewloadedforfirsttime=NO;
if([SKPaymentQueue canMakePayments])
{
// if (![[NSUserDefaults standardUserDefaults] valueForKey:#"isStorePurchased"])
// {
[self requestProductData];
//}
NSLog(#"IN-APP:can make payments");
}
else {
NSLog(#"IN-APP:can't make payments");
}
[self performSelector:#selector(buyProduct) withObject:nil afterDelay:2.0];
}
- (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];
break;
case SKPaymentTransactionStatePurchasing:
NSLog(#"Purchasing...");
break;
default:
break;
}
}
}
you yourself have inside your code the case of SKPaymentTransactionStateRestored which tells when a product is being restored.
You need to add code that executes the restoreCompletedTransactions method...
add the [self checkPurchasedItems]; in the App's initial launch somewhere like the root view controller's viewDidLoad method to get the purchase button logic to show up..
keep the buttons.enabled = NO... this way the buttons are only enabled when the return methods arrive telling us what we already purchased... you should store those booleans for offline mode.
when the transactions are restored mark the buttons as enabled and/or hidden appropriately.
good luck!

How to display an activity indicator while loading in app purchase?

I have a button that calls the in app purchase feature. I would to display a loading wheel while it is loading the product and the dismiss it when the UIAlertView to confirm the purchase appears. I am using the MBAlertView to show other messages in my app and I would to use it also here.
How can I do it? I want to display it when the user presses the button and dismiss it when it receives a response.
Here is my code at the moment!
- (IBAction)buyCoffeeInAppPurchase:(id)sender {
SKProductsRequest *request= [[SKProductsRequest alloc]
initWithProductIdentifiers: [NSSet setWithObject: #"com.giovannibalestra.emergencycall.Thankyoudeveloper"]];
request.delegate = self;
[request start];
// I should add something like this line of code to show the activity indicator but I can only set hidesAfter some seconds
// [MBHUDView hudWithBody:#"Wait." type:MBAlertViewHUDTypeActivityIndicator hidesAfter:4.0 show:YES];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
NSArray *myProduct = response.products;
NSLog(#"%#",[[myProduct objectAtIndex:0] productIdentifier]);
SKPayment *newPayment = [SKPayment paymentWithProduct:[myProduct objectAtIndex:0]];
[[SKPaymentQueue defaultQueue] addPayment:newPayment];
}
- (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)completeTransaction:(SKPaymentTransaction *)transaction {
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
if (transaction.error.code != SKErrorPaymentCancelled)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Purchase Unsuccessful"
message:#"Your purchase failed. Please try again."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
For show loading you can also use MBProgressHUD. Its a easy way to show loading process. Download MBProgressHUD.h & .m file from internet & just copy in xcode project.
HOW TO USE: Import this #import "MBProgressHUD.h" in your .h & .m files & also this MBProgressHUD *HUD; in .h file.
Then in .m file your code looks like:
- (IBAction)buyCoffeeInAppPurchase:(id)sender {
HUD = [[MBProgressHUD alloc] initWithFrame:CGRectMake(0, 0, 320, 460) ];
HUD.labelText = #"Fetching...";
[self.view addSubview:HUD];
[HUD show:YES];
SKProductsRequest *request= [[SKProductsRequest alloc]
initWithProductIdentifiers: [NSSet setWithObject: #"com.giovannibalestra.emergencycall.Thankyoudeveloper"]];
request.delegate = self;
[request start];
// I should add something like this line of code to show the activity indicator but I can only set hidesAfter some seconds
// [MBHUDView hudWithBody:#"Wait." type:MBAlertViewHUDTypeActivityIndicator hidesAfter:4.0 show:YES];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
NSArray *myProduct = response.products;
NSLog(#"%#",[[myProduct objectAtIndex:0] productIdentifier]);
SKPayment *newPayment = [SKPayment paymentWithProduct:[myProduct objectAtIndex:0]];
[[SKPaymentQueue defaultQueue] addPayment:newPayment];
[HUD hide:YES];
[HUD removeFromSuperViewOnHide];
}
- (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)completeTransaction:(SKPaymentTransaction *)transaction {
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
if (transaction.error.code != SKErrorPaymentCancelled)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Purchase Unsuccessful"
message:#"Your purchase failed. Please try again."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)paymentQueue:(SKPaymentQueue *)queue
updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
if (transaction.transactionState == SKPaymentTransactionStatePurchased) {
[self completeTransaction:transaction];
}
if (transaction.transactionState == SKPaymentTransactionStateFailed) {
[self failedTransaction:transaction];
}
if (transaction.transactionState == SKPaymentTransactionStateRestored) {
[self restoreTransaction:transaction];
}
else {
// Do something.
}
// You can dismiss your Activity Indicator (MBHUDView) here.
}
}
Hi Simply apply the activity indicator when user clicks on purchase button and stop the activity indicator after this method - (void)completeTransaction:(SKPaymentTransaction *)transaction. Don't forget to stop in failed transaction too, other wise activity indicator start animating. Some times activity indicator needs to calls through threads is they not visible. So please try that too.

Inapppurchase SKProductsRequest Crash my application in ios5

my store kit class crash for SKProductsRequest start i am not experienced inapppurchase concept my class working perfectly in iOS 4.3 sdk not iOS 5 sdk. i am not getting error on console and my application crashed before after SKProductsRequest start please can any one help me how to fix this issue here's my code:
#import "StorePurchase.h"
#implementation StorePurchase
#synthesize request = _request;
- (void)loadStore {
if ([SKPaymentQueue canMakePayments]) {
NSLog(#"Parental-controls are disabled");
self.request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:#"com.mycompany.app"]];
self.request.delegate = self;
[self.request start];
}
else {
NSLog(#"Parental-controls are enabled");
}
}
static bool hasAddObserver=NO;
- (void)purchase {
if (!hasAddObserver) {//flag to fix this bug
/*=====================================*/
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
hasAddObserver=YES;
}
SKMutablePayment *payment = [[SKMutablePayment alloc] init] ;
payment.productIdentifier = #"com.mycompany.app";
payment.quantity = 1;
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
SKProduct *validProduct = nil;
int count = [response.products count];
if (count > 0)
{
validProduct = [response.products objectAtIndex:0];
NSLog(#"Products found,Magic Box!");
[[NSNotificationCenter defaultCenter] postNotificationName:kProductsLoadedNotification object:#"Product Found..!"];
} else if (!validProduct)
{
NSLog(#"No products available");
[[NSNotificationCenter defaultCenter] postNotificationName:kProductsLoadedNotification object:#"Product Not Found..!"];
}
}
- (void)provideContent:(NSString *)productIdentifier {
NSLog(#"Toggling flag for: %#", productIdentifier);
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
//[_purchasedProducts addObject:productIdentifier];
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchasedNotification object:productIdentifier];
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"completeTransaction...");
//[self recordTransaction: transaction];
[self provideContent: transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"restoreTransaction...");
//[self recordTransaction: transaction];
[self provideContent: transaction.originalTransaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Transaction error: %#", transaction.error.localizedDescription);
}
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchaseFailedNotification object:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{
NSLog(#"<><Canceled!><>");
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchaseCanceledNotification object:error];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
// [self completeTransaction:transaction];
break;
case SKPaymentTransactionStatePurchased:
NSLog(#"Purchased");
[self completeTransaction:transaction];
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
NSLog(#"Restored");
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"An error encounterd");
}
else {
NSLog(#"Cancelled!");
}
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[self failedTransaction:transaction];
break;
}
}
}
i am call the loadStore method after getting the error
SKProductsRequest doesn't call the - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response method before crash my app!
What's Wrong in my code how to fix!
Thanks in Advance!
i have done code for inapppurchase in my application using this code gets no issues
- (void)loadStore
{
// restarts any purchases if they were interrupted last time the app was open
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
// get the product description (defined in early sections)
[self requestProUpgradeProductData];
}
- (void)requestProUpgradeProductData
{
NSSet *productIdentifiers = [NSSet setWithObject:kInAppPurchaseProUpgradeProductId];
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
// we will release the request object in the delegate callback
}
After this it will call this method
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSArray *products = response.products;
proUpgradeProduct = [products count] == 1 ? [[products objectAtIndex:0] retain] : nil;
if (proUpgradeProduct)
{
NSLog(#"Product title: %#" , proUpgradeProduct.localizedTitle);
NSLog(#"Product description: %#" , proUpgradeProduct.localizedDescription);
NSLog(#"Product price: %#" , proUpgradeProduct.price);
NSLog(#"Product id: %#" , proUpgradeProduct.productIdentifier);
if ([self canMakePurchases]) {
if ([self respondsToSelector:#selector(purchaseProUpgrade)]) {
[self purchaseProUpgrade];
}
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[self languageSelectedStringForKey:#"Error"] message:#"Cannot connect to Store.\n Please Enable the Buying in settings" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
}
}
for (NSString *invalidProductId in response.invalidProductIdentifiers)
{
[SVProgressHUD dismiss];
[cancelButton setEnabled:YES];
[buyNowButton setEnabled:YES];
[restoreButton setEnabled:YES];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning" message:#"Error occured" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
[alert release];
NSLog(#"Invalid product id: %#" , invalidProductId);
}
// finally release the reqest we alloc/init’ed in requestProUpgradeProductData
[productsRequest release];
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
[self recordTransaction:transaction];
[self provideContent:transaction.payment.productIdentifier];
[self finishTransaction:transaction wasSuccessful:YES];
}
- (void)purchaseProUpgrade
{
[SVProgressHUD showInView:self.view status:[self languageSelectedStringForKey:#"Connecting Store"] networkIndicator:YES];
SKPayment *payment = [SKPayment paymentWithProductIdentifier:kInAppPurchaseProUpgradeProductId];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)recordTransaction:(SKPaymentTransaction *)transaction
{
if ([transaction.payment.productIdentifier isEqualToString:kInAppPurchaseProUpgradeProductId])
{
// save the transaction receipt to disk
[[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:#"proUpgradeTransactionReceipt" ];
[[NSUserDefaults standardUserDefaults] synchronize];
}
}
Finally this method
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
// remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, #"transaction" , nil];
if (wasSuccessful)
{
//Write your transaction complete statement required for your project
}
Follow any of this two Tutorieals:
Tutorial for in app purchase
OR follow RMStore Verification: Here.

what is the alternative solution for paymentWithProductIdentifier?

Hi i am using in APP purchase in my project . When i run this project everything works fine, except i am getting a warning message saying that "paymentWithProductIdentifier is deprecated", I gone through the similar questions that are asked in stack overflow but i didn't satisfied. I shown you my coding that i used in the project below
SKPayment *payment=[SKPayment paymentWithProductIdentifier:#"com.mycompany.dmaker.maker1"];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
Can anyone tell me
1)the alternative for this warning.
2)or tell me whether this project approve in appstore if i use this existing code.
Try using this:
SKProduct *selectedProduct = <#from the products response list#>;
SKPayment *payment = [SKPayment paymentWithProduct:selectedProduct];
[[SKPaymentQueue defaultQueue] addPayment:payment];
You can replace paymentWithProductIdentifier: with following codes:
// SKPayment *payment = [SKPayment paymentWithProductIdentifier:productId];
// [[SKPaymentQueue defaultQueue] addPayment:payment];
NSSet *productIdentifiers = [NSSet setWithObject:productId];
self.productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
self.productsRequest.delegate = self; // your wrapper for IAP or AppDelegate or anything
[self.productsRequest start];
while productsRequest is a retain property.
And implement a SKProductsRequestDelegate method:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
for (SKProduct *product in response.products) {
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
self.productsRequest = nil;
}
You have 3 options:
suppress this warning with preprocessor definition:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
SKPayment *payment=[SKPayment paymentWithProductIdentifier:#"com.mycompany.dmaker.maker1"];
#pragma clang diagnostic pop
[[SKPaymentQueue defaultQueue] addPayment:payment];
create SKMutablePayment instead of SKPayment:
SKMutablePayment *payment = [[SKMutablePayment alloc] init];
payment.productIdentifier = #"com.mycompany.dmaker.maker1";
payment.quantity = 1;
[[SKPaymentQueue defaultQueue] addPayment:payment];
use paymentWithProduct: convenience initializer:
SKPayment *payment = [SKPayment paymentWithProduct:<# product that you received in productsRequest:didReceiveResponse: #>];
[[SKPaymentQueue defaultQueue] addPayment:payment];
You could use the following code instead, it does have a little extra that you may already have, but just to make sure
#define kInAppPurchaseId "(your product ID here)"
- (void)makePurchase{
//call this when you would like to begin the purchase
//like when the user taps the "purchase" button
NSLog(#"User requests to make purchase");
if([SKPaymentQueue canMakePayments]){
NSLog(#"User can make payments");
SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kInAppPurchaseId]];
productsRequest.delegate = self;
[productsRequest start];
}
else{
//the user is not allowed to make payments
NSLog(#"User cannot make payments due to parental controls");
}
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
SKProduct *validProduct = nil;
int count = [response.products count];
if(count > 0){
validProduct = [response.products objectAtIndex:0];
NSLog(#"Products Available!");
[self purchase:validProduct];
}
else if(!validProduct){
NSLog(#"No products available");
}
}
- (IBAction)purchase:(SKProduct *)product{
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
I use this code in one off my applications, so it should work.

InApp Purchase SKPaymentQueue finish Transaction doesn't work

i am working inapp purchase project in iOS sdk.i have prepared inapp purchase class for purchasing app from appstore with enable inner contents of the project.but, my problem is SKPaymentQueue doesn't finish working on my class.here's code of my inapp purchase class:
- (void)purchase {
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
SKPayment *payment = [SKPayment paymentWithProductIdentifier:#"com.test"];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)provideContent:(NSString *)productIdentifier {
NSLog(#"Toggling flag for: %#", productIdentifier);
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
//[_purchasedProducts addObject:productIdentifier];
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchasedNotification object:productIdentifier];
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"completeTransaction...");
//[self recordTransaction: transaction];
[self provideContent: transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"restoreTransaction...");
//[self recordTransaction: transaction];
[self provideContent: transaction.originalTransaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Transaction error: %#", transaction.error.localizedDescription);
}
[[NSNotificationCenter defaultCenter] removeObserver:self name:kProductPurchaseFailedNotification object:transaction];
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchaseFailedNotification object:transaction];
//[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationName" object:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
break;
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"An error encounterd");
}
else {
NSLog(#"Cancelled!");
}
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[self failedTransaction:transaction];
break;
}
}
}
- (void)dealloc
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[request release];
[super dealloc];
}
that's line doesn't work on my class [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; transaction doesn't finish.
and my another problem is nsnotificationcenter calls multiple times like if i click first time it's call only one time no problem,another time it's nsnotificationcenter calls 3 times.
i got solution your problem is addTransaction server duplicate to your issue,
try below code it's must working:
static bool hasAddObserver=NO;
- (void)purchase {
if (!hasAddObserver) {//flag to fix this bug
/*=====================================*/
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
hasAddObserver=YES;
}
SKPayment *payment = [SKPayment paymentWithProductIdentifier:#"com.test"];
//[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)provideContent:(NSString *)productIdentifier {
NSLog(#"Toggling flag for: %#", productIdentifier);
[[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
//[_purchasedProducts addObject:productIdentifier];
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchasedNotification object:productIdentifier];
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"completeTransaction...");
//[self recordTransaction: transaction];
[self provideContent: transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"restoreTransaction...");
//[self recordTransaction: transaction];
[self provideContent: transaction.originalTransaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Transaction error: %#", transaction.error.localizedDescription);
}
[[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchaseFailedNotification object:transaction];
//[[NSNotificationCenter defaultCenter] postNotificationName:#"NotificationName" object:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
break;
case SKPaymentTransactionStatePurchased:
//[self completeTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
if (transaction.error.code != SKErrorPaymentCancelled) {
NSLog(#"An error encounterd");
}
else {
NSLog(#"Cancelled!");
}
//[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
[self failedTransaction:transaction];
break;
}
}
}
- (void)dealloc
{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[request release];
[super dealloc];
}
Welcome!
To fix this problem just add [[SKPaymentQueue defaultQueue]removeTransactionObserver:self];
right after [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
You can do like this:
- (void)buyProduct:(SKProduct *)product {
NSLog(#"Buying %#...", product.productIdentifier);
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)validateReceiptForTransaction:(SKPaymentTransaction *)transaction {
VerificationController * verifier = [VerificationController sharedInstance];
[verifier verifyPurchase:transaction completionHandler:^(BOOL success) {
if (success) {
NSLog(#"Successfully verified receipt!");
[self provideContentForProductIdentifier:transaction.payment.productIdentifier];
} else {
NSLog(#"Failed to validate receipt.");
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
}];
}
#pragma mark SKPaymentTransactionOBserver
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
NSLog(#"Prossing.............");
break;
case SKPaymentTransactionStatePurchased:
{
[self completeTransaction:transaction];
NSError* error;
NSDictionary* jsonDict = [NSJSONSerialization
JSONObjectWithData:transaction.transactionReceipt
options:kNilOptions
error:&error];
NSLog(#"JSON Receipt: %#",jsonDict);
[[NSUserDefaults standardUserDefaults] setObject:jsonDict forKey:#"A"];
NSLog(#"Purchase was a Success.....");
}
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
NSLog(#"Purchase cancelled");
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
default:
break;
}
}
}
- (void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"completeTransaction...");
[self validateReceiptForTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"restoreTransaction...");
[self validateReceiptForTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction {
NSLog(#"failedTransaction...");
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
if (transaction.error.code != SKErrorPaymentCancelled)
{
NSLog(#"Transaction error: %#", transaction.error.localizedDescription);
MedPulseAppDelegate *appdelegate =( MedPulseAppDelegate *)[[UIApplication sharedApplication]delegate];
[appdelegate hideLoading];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void)provideContentForProductIdentifier:(NSString *)productIdentifier {
if ([productIdentifier isEqualToString:kMDPulseSubscriptionProductIdentifier]) {
[self purchaseSubscriptionWithMonths:1];
}
[[NSNotificationCenter defaultCenter] postNotificationName:IAPHelperProductPurchasedNotification object:productIdentifier userInfo:nil];
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
NSLog(#"%s","User Cancel.");
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
NSLog(#"Restore completed transactions finished.");
NSLog(#" Number of transactions in queue: %d", [[queue transactions] count]);
for (SKPaymentTransaction *trans in [queue transactions])
{
NSLog(#" transaction id %# for product %#.", [trans transactionIdentifier], [[trans payment] productIdentifier]);
NSLog(#" original transaction id: %# for product %#.", [[trans originalTransaction] transactionIdentifier],
[[[trans originalTransaction] payment]productIdentifier]);
if ([[[trans payment] productIdentifier] isEqual: kMDPulseSubscriptionProductIdentifier]) {
NSLog(#"Purchase Restored");
// Do your stuff to unlock
}
}
}
- (void)restoreCompletedTransactions
{
NSLog(#"Restore Tapped in transaction process");
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
Welcome!
If you have any doubt comment it down