Note that there are some explanatory texts on larger screens.

plurals
  1. POiPhone In App Purchase issue
    text
    copied!<p>I use In App Purchase in my application, but I have problem when I'm testing that. I have four consumable products. Information about that products I show in <code>tableview</code>. Sometimes when I click a button to buy some product I get a transaction state <code>SKPaymentTransactionStateFailed</code> in <code>updatedTransaction</code> function but <code>transaction.error localizedFailureReason</code> is always <code>null</code>. Once I noticed that one transaction was updated two times (in <code>updatedTransaction</code> function transaction with the same <code>transactionIdentifier</code> comes, state of transaction is <code>SKPaymentTransactionStatePurchased</code>) - is then that product two times purchased?.</p> <p>So I have no idea where is the problem. Please help me.</p> <p>I use that class to manage In App Purchase:</p> <pre><code>@implementation InAppPurchaseManager @synthesize upgradeProducts; @synthesize productsRequest; @synthesize delegate; - (id) init { self = [super init]; if (!self) return nil; if ([SKPaymentQueue canMakePayments]) { [self loadStore]; [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; } upgradeProducts = [[NSMutableArray alloc] init]; delegate = nil; return self; } + (InAppPurchaseManager *) sharedInstance { static InAppPurchaseManager *myInstance = nil; if (nil == myInstance) { myInstance = [[[self class] alloc] init]; } return myInstance; } - (void) loadStore { NSSet *productsIdentifiers = [[NSSet alloc] initWithObjects:PRODUCT_1_ID, PRODUCT_2_ID, PRODUCT_3_ID, PRODUCT_4_ID, nil]; [self requestUpgradeProductsData:productsIdentifiers]; [productsIdentifiers release]; } - (void) requestUpgradeProductsData:(NSSet *) productIdentifiers { productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers]; productsRequest.delegate = self; [productsRequest start]; } - (void) productsRequest:(SKProductsRequest *) request didReceiveResponse:(SKProductsResponse *) response { [upgradeProducts removeAllObjects]; for (int i = 0; i &lt; [response.products count]; i++) { SKProduct *product = [response.products objectAtIndex:i]; UpgradeProduct *upgradeProduct = [[UpgradeProduct alloc] initWithProductID:product.productIdentifier]; upgradeProduct.title = product.localizedTitle; upgradeProduct.description = product.localizedDescription; NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init]; [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4]; [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle]; [numberFormatter setLocale:product.priceLocale]; NSString *price = [numberFormatter stringFromNumber:product.price]; [numberFormatter release]; upgradeProduct.price = price; [self.upgradeProducts addObject:upgradeProduct]; [upgradeProduct release]; } [productsRequest release]; if ([self.delegate respondsToSelector:@selector(didLoadStore:)]) [self.delegate didLoadStore:self.upgradeProducts]; } + (BOOL) canMakePurchases { if ([SKPaymentQueue canMakePayments]) return YES; else { [Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title") message:NSLocalizedString(@"You are not authorized to purchase from AppStore", @"Payment Error Alert Text when user cannot make payments from store")]; return NO; } } - (void) purchaseUpgrade:(NSString *) productIdentifier { if ([InAppPurchaseManager canMakePurchases]) { SKPayment *payment = [SKPayment paymentWithProductIdentifier:productIdentifier]; [[SKPaymentQueue defaultQueue] addPayment:payment]; } } - (void) recordTransaction:(SKPaymentTransaction *) transaction { [[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"upgradeTransactionReceipt" ]; [[NSUserDefaults standardUserDefaults] synchronize]; } - (void) finishTransaction:(SKPaymentTransaction *) transaction { [self paymentSucceeded:transaction]; [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; } - (void) paymentSucceeded:(SKPaymentTransaction *) transaction { // provide content here if ([self.delegate respondsToSelector:@selector(didFinishPaymentTransaction)]) [self.delegate didFinishPaymentTransaction]; } - (void) completeTransaction:(SKPaymentTransaction *) transaction { [self recordTransaction:transaction]; [self finishTransaction:transaction]; } - (void) restoreTransaction:(SKPaymentTransaction *) transaction { [self recordTransaction:transaction.originalTransaction]; [self finishTransaction:transaction]; } - (void) failedTransaction:(SKPaymentTransaction *) transaction { if (transaction.error.code != SKErrorPaymentCancelled) { NSMutableString *messageToBeShown = [[NSMutableString alloc] init]; if ([transaction.error localizedFailureReason] != nil) { [messageToBeShown setString:[NSString stringWithFormat:@"%@ %@", NSLocalizedString(@"Reason:", @"Reason Text in alert when payment transaction failed"), [transaction.error localizedFailureReason]]]; if ([transaction.error localizedRecoverySuggestion] != nil) [messageToBeShown appendFormat:@", %@ %@", NSLocalizedString(@"You can try:", @"Text for sugesstion in alert when payment transaction failed"), [transaction.error localizedRecoverySuggestion]]; } [Global showAlertViewWithTitle:NSLocalizedString(@"Unable to complete your purchase", @"Payment transaction failed alert title") message:messageToBeShown]; [messageToBeShown release]; if ([self.delegate respondsToSelector:@selector(didFailedPaymentTransaction)]) [self.delegate didFailedPaymentTransaction]; } else { if ([self.delegate respondsToSelector:@selector(didCancelPaymentTransaction)]) [self.delegate didCancelPaymentTransaction]; } [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; } - (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; default: break; } } } - (void) request:(SKRequest *) request didFailWithError:(NSError *) error { [Global showAlertViewWithTitle:NSLocalizedString(@"Payment Error", @"Payment Error Alert Title") message:[NSString stringWithFormat:@"%@, %@", NSLocalizedString(@"Could not contact App Store properly", @"Alert text when request did fail"), [error localizedDescription]]]; } - (void) dealloc { [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; [upgradeProducts release]; if (productsRequest) productsRequest = nil; [super dealloc]; } @end </code></pre> <p>In AppDelegate in function didFinishLaunchingWithOptions I make that:</p> <pre><code>[InAppPurchaseManager sharedInstance]; </code></pre> <p>In Purchase View when I click a button I make:</p> <pre><code>UpgradeProduct *selectedProduct = [self.faxProducts objectAtIndex:[purchaseButton.identifier intValue]]; if (selectedProduct) { [[InAppPurchaseManager sharedInstance] purchaseUpgrade:selectedProduct.productID]; } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload