paymentQueue:updatedTransactions gets called when it shouldn't? - iphone

I'm having a weird problem with an in-app purchase...
After I'm requesting the product information, sometimes the paymentQueue:updatedTransactions gets called automatically for some reason.
In my store's viewDidLoad method, I initialize and start the request:
- (void)viewDidLoad
{
[super viewDidLoad];
productsArray = [[NSArray alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
NSSet *productIdentifiers = [NSSet setWithObjects:PRODUCT_ID, nil];
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
Then I get a response:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
productsArray = [[NSArray alloc] initWithArray:response.products];
NSLog(#"Products Count: %d",[productsArray count]);
NSLog(#"Invalid Products Count: %d",[response.invalidProductIdentifiers count]);
if ([productsArray count] > 0)
{
NSLog(#"Product title: %#" ,[productsArray objectAtIndex:0]);
[self hideLoadingView];
} else {
UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:#"No products found"
message:#"There might have been a problem. Please try again soon." delegate:self
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
[alertView release];
[self hideLoadingView];
[purchaseBtn setEnabled:NO];
}
[productsRequest release];
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
}
This is where I expect the process to end, and wait for the user to tap the buy button... but sometimes (like, 70% of the times), I get a username/password alert box pop-up in order to buy the item... but the user didn't tap anything... (and if the user is already "logged in", then it buys the item without asking. Which is NOT how it should be.
This is the method that is being called automatically sometimes:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
NSLog(#"updated transaction");
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
NSLog(#"transationStatePurchased");
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(#"transationStateFailed");
[self failedTransaction:transaction];
break;
default:
break;
}
}
}
and this is the IBAction of the buy button:
-(IBAction)buyItem:(id)sender {
[self showLoadingView];
SKPayment *payment = [SKPayment paymentWithProductIdentifier:[(SKProduct *)[productsArray objectAtIndex:0] productIdentifier]];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
}
I thought that the user/password alert box of StoreKit shouldn't get displayed until I call the defaultQueue's "addPayment" method, which appears ONLY in the IBAction.
Any ideas?
Thanks!

Once you add a transaction observer iOS will check the default Queue if there is any non completed transaction (which mean you didn't finish it) so it will show the alert box every time there is a transaction until you finish it even if you didn't do any action to add a new payment.

Related

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.

Implementing in app purchase and its restoration in iphone

I have implemented in app purchase in one of my application using MKStoreManager.Now got a new guideline from apple that if you are doing in app purchase,you have to give the user,the option for restoring the already purchased application.So i have done like this.On the 'restore' button click,this method is called.
- (void) checkPurchasedItems
{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
and from here,this method is fired
- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{
NSMutableArray* purchasableObjects = [[NSMutableArray alloc] init];
NSLog(#"received restored transactions: %i", queue.transactions.count);
for (SKPaymentTransaction *transaction in queue.transactions)
{
NSString *productID = transaction.payment.productIdentifier;
[purchasableObjects addObject:productID];
}
}
But now i have a doubt that how can i check this restoration is working or not.Can anyone guide me.thanks in advance.
Here is how you implement the Restoration
- (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
}

Error Domain=SKErrorDomain Code=3 "Cannot connect to iTunes Store" UserInfo=0x1aaf40 {NSLocalizedDescription=Cannot connect to iTunes Store}

Currently I'm working on in-App Purchase functionality, and I am getting below of the error
"Error Domain=SKErrorDomain Code=3 "Cannot connect to iTunes Store" UserInfo=0x1aaf40 {NSLocalizedDescription=Cannot connect to iTunes Store}"
Here is the step.
1) First I have create a one application "inAppPro" and it is under (Status) : "Prepare for upload"
2) I have added 4 Non-Consumable product. and also fill related details.
3) I have also create test user (sandbox) for test in-App purchase product.
4) I have also created provision profile with enable inApp Purchase.
5) I have also created APP ID without (*) wild card.
Here is the code which are currently I'm using.
- (void)viewDidLoad
{
Detail1 *observer = [[Detail1 alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:observer];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
if ([SKPaymentQueue canMakePayments])
{
NSString *product = [NSString stringWithFormat:#"com.companyname.inAppDemo.module%d",ApplicationDelegate.objectID];
NSLog(#"In-App product for request = %#", product);
SKPayment *payment = [SKPayment paymentWithProductIdentifier:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"MyApp" message:#"You are not authorized to purchase from AppStore"
delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}
- (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)
{
// Optionally, display an error here.
NSLog(#"%#",transaction.error);
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
//[[MKStoreManager sharedManager] provideContent: transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction
{
//[[MKStoreManager sharedManager] provideContent: transaction.originalTransaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
-(IBAction)btnpurchase:(id)sender
{
NSLog(#"ProductStatus = %#", ApplicationDelegate.productStatus);
if ([ApplicationDelegate.productStatus isEqualToString:#"FREE"])
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil message:#"This is free for you so ENJOY it!!!" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil,nil];
[alert show];
[alert release];
}
else if ([ApplicationDelegate.productStatus isEqualToString:#"PAID"])
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:nil message:#"You have already purchase it!!!" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil,nil];
[alert show];
[alert release];
}
else
{
NSLog(#"Detail1 id for product = %d", ApplicationDelegate.objectID);
NSString *product = [NSString stringWithFormat:#"com.companyname.inAppDemo.module%d",ApplicationDelegate.objectID];
NSLog(#"In-App product-id = %#", product);
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:product,nil]];
request.delegate = self;
[request start];
}
}
Please anyone help me out.
Thanks in advance.
You must have valid contracts in effect in the "Contracts, Tax, and Banking" Section.
And of course, make sure that you use a correct Provisioning Profile and that you have enabled in App Purchase for that ID, and (last) that you have added purchasable items in iTunes Connect (which you did, as your screenshots show).

Inapp Purchase is succeeded but content is not unlock in iPhone app.. Why?

In My iphone app i have used In App purchase. All the things are working and the contents are in Resource folder. After successful transaction i have used a Sql Query to insert data in Sqlite database. I have Uploaded this app in App Store and find that after successful transaction the payment is taken from users but the content is not inserted in database and not Showed in app. Please help me. i am stressed on this Point. Due to this i have removed my app form App Store.
In this code after successful finding list of In App Purchases i am using method
For better Understanding i am putting my Some code here:
- (void)insertNewObject {
// Create a new instance of the entity managed by the fetched results controller.
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
// Save the context.
NSError *error = nil;
if (![context save:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
*/
// NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
}
-(void)updateObject {
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
// Save the context.
NSError *error = nil;
if (![context save:&error]) {
abort();
}
}
#pragma mark -
#pragma mark Store request
- (void) requestProductData {
request= [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:[arrayProductID objectAtIndex:b-2]]];//#"Scaringmirror11"
request.delegate = self;
[request start];
}
- (void) startPurchase {
//int newB=b-2;
SKPayment *payment = [SKPayment paymentWithProductIdentifier:[arrayProductID objectAtIndex:b-2]];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
#pragma mark Store delegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSArray *myProduct = response.products;
if (myProduct == nil || [myProduct count] == 0)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ALERT_TITLE message:#"Missing product from App store.\n"
delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
SKProduct *product;
BOOL existProduct = NO;
for (int i=0; i<[myProduct count]; i++) {
product = (SKProduct*)[myProduct objectAtIndex:0];
if ([product.productIdentifier isEqualToString:[arrayProductID objectAtIndex:b-2]]) {
existProduct = YES;
//[[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:#"proUpgradeTransactionReceipt" ];
//[[NSUserDefaults standardUserDefaults] synchronize];
break;
}
}
if (existProduct == NO) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ALERT_TITLE message:#"Missing product from App store.No match Identifier found.\n"
delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
[request autorelease];
[self startPurchase];
}
#pragma mark Store delegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSArray *myProduct = response.products;
if (myProduct == nil || [myProduct count] == 0)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ALERT_TITLE message:#"Missing product from App store.\n"
delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
SKProduct *product;
BOOL existProduct = NO;
for (int i=0; i<[myProduct count]; i++) {
product = (SKProduct*)[myProduct objectAtIndex:0];
if ([product.productIdentifier isEqualToString:[arrayProductID objectAtIndex:b-2]]) {
existProduct = YES;
//[[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:#"proUpgradeTransactionReceipt" ];
//[[NSUserDefaults standardUserDefaults] synchronize];
break;
}
}
if (existProduct == NO) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ALERT_TITLE message:#"Missing product from App store.No match Identifier found.\n"
delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
return;
}
[request autorelease];
[self startPurchase];
}
#pragma mark observer delegate
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions)
{
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
NSLog(#"Success");
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
NSLog(#"Failed");
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
default:
break;
}
}
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction {
//[[NSUserDefaults standardUserDefaults] setBool:YES forKey:REGISTRATION_KEY];
registered = YES;
//NSData *receiptData = [transaction transactionReceipt];
//NSString *str =[NSString string
//[[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:#"proUpgradeTransactionReceipt" ];
//[self registeredEnable];
// Remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
[sqlite insertIntoScaryImage:[arrayGetMoreScaryImage objectAtIndex:b] add:[arrayGetMoreScarySound objectAtIndex:b]];
}
- (void) restoreTransaction: (SKPaymentTransaction *)transaction {
//[[NSUserDefaults standardUserDefaults] setBool:YES forKey:REGISTRATION_KEY];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ALERT_TITLE message:#"Purchase success."
delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
//[sq];
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction {
if (transaction.error.code != SKErrorPaymentCancelled)
{
// Optionally, display an error here.
NSString *stringError = [NSString stringWithFormat:#"Payment Cancelled\n\n%#", [transaction.error localizedDescription]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:ALERT_TITLE message:stringError
delegate:self cancelButtonTitle:#"Close" otherButtonTitles:nil];
[alert show];
[alert release];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
Please have a look and tell me where should i insert data in database so that i will able to provide data to users after Successful in app Purchase.
Thanks in Advance
You should implement your unlocking functionality into the payment observer, right after you receive confirmation that the payment is all right.
Your implementation of the observer is kinda strange, I guess it's not working.
EDIT:
your observer class
#import Foundation/Foundation.h
#import StoreKit/StoreKit.h
#interface InAppPurchaseObserver : NSObject {
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;
#end
#import "InAppPurchaseObserver.h"
#implementation InAppPurchaseObserver
// The transaction status of the SKPaymentQueue is sent here.
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for(SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
// Item is still in the process of being purchased
NSLog(#"Processing!!!");
break;
case SKPaymentTransactionStatePurchased:
// Item was successfully purchased!
// --- UNLOCK FEATURE OR DOWNLOAD CONTENT HERE ---
// The purchased item ID is accessible via
// transaction.payment.productIdentifier
// After customer has successfully received purchased content,
// remove the finished transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
break;
case SKPaymentTransactionStateRestored:
// Verified that user has already paid for this item.
// Ideal for restoring item across all devices of this customer.
// --- UNLOCK FEATURE OR DOWNLOAD CONTENT HERE ---
// The purchased item ID is accessible via
// transaction.payment.productIdentifier
// After customer has restored purchased content on this device,
// remove the finished transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
break;
case SKPaymentTransactionStateFailed:
// Purchase was either cancelled by user or an error occurred.
NSLog(#"Failed!!!");
if (transaction.error.code != SKErrorPaymentCancelled) {
// A transaction error occurred, so notify user.
NSLog(#"Cancelled!!!");
}
// Finished transactions should be removed from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
break;
}
}
}
#end
implementation
- (void) requestProductData {
inappObserver = [[InAppPurchaseObserver alloc] init];
request= [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:[arrayProductID objectAtIndex:b-2]]];//#"Scaringmirror11"
request.delegate = self;
[request start];
}
- (void) startPurchase {
//int newB=b-2;
SKPayment *payment = [SKPayment paymentWithProductIdentifier:[arrayProductID objectAtIndex:b-2]];
[[SKPaymentQueue defaultQueue] addTransactionObserver:inappObserver];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}

Apple In app purchase StoreKit error

I am implementing in app purchase feature for a bookshelf but an error message RANDOMLY appear during purchasing books.
The error message is
"Payment requests are restricted to products returned as valid via Store Kit's didReceiveResponse method."
I find the document in apple
http://developer.apple.com/library/ios/#qa/qa2010/qa1691.html
but it does not help to solve the problem...
in the same time observer print out another error : "Can't connect to the iTunes Store".
my in app purchase logic flow:
APP START:
- (void) requestProductDataWithSet:(NSSet*)_set
{
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: _set];
request.delegate = self;
[request start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
//setup UI here
}
PURCHASE:
- (void) purchase:(SKProduct *)product
{
if (!product || !verified) {
return;
}
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject:product.productIdentifier]];
request.delegate = self;
[request start];
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{
if ([SKPaymentQueue canMakePayments] && [response.products count] > 0)
{
NSLogInfo(#"xxxxxxxxx Make payment xxxxxxxxx");
SKPayment *payment = [SKPayment paymentWithProduct:[response.products objectAtIndex:0]];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Purchase" message:#"You are not authorized to purchase from AppStore"
delegate:self cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
[alert release];
}
}
Observer:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions)
{
NSLogInfo(#"updatedTransactions transactionState:%d, productIdentifier:%#",transaction.transactionState,transaction.payment.productIdentifier);
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased:
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
default:
break;
}
}
}
It looks like the problem isn't on your side. According to Technical Q&A QA1691, your code is fine.
Try changing:
SKPayment *payment = [SKPayment paymentWithProduct:[response.products objectAtIndex:0]];
to:
SKPayment *payment = [SKPayment paymentWithProductIdentifier:[response.products objectAtIndex:0].productIdentifier];
I had the same problem as you and this change worked for me.