Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,561
6,059
Edit: I'm not sure if anything in my first post is terribly relevant to the issue I'm having... maybe it'd be best to skip to my follow up post?

I'd like to make it so that users of my app can pay to remove an iAd banner from it.

There's a "Remove Ads" button just above the banner. Here's the code for when it's hit:

Code:
-(IBAction)removeAds:(id)sender
{
    if ([SKPaymentQueue canMakePayments])
    {
        SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject: @"findItFirstRemoveAds"]];
        request.delegate = self;
        [request start];
    }
    else
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"In-App Purchases are Disabled"
                                                        message:@"The ads could not be removed because In-App Purchases are disabled on this device. To change this, go to your device Settings, choose General, then Restrictions, and enable In-App Purchases."
                                                       delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        alert.delegate = self;
        [alert show];
        [alert release]; 
    }
}

This object is the delegate for the purchase. Initially, my program would crash when it tried to run the next section, but checking the crash logs, I determined that the app store was sending back a response.products array that was empty. So I added a check to see how big the array is. If it's anything other than 1, it has to be an issue, right?

Code:
#pragma mark - SKRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    if ([response.products count] == 1)
    {
        SKProduct *adRemovalProduct = [response.products objectAtIndex:0];
    
        NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
        [numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
        [numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
        [numberFormatter setLocale:adRemovalProduct.priceLocale];
    
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:adRemovalProduct.localizedTitle
                                                        message:[NSString stringWithFormat:@"%@ %@", adRemovalProduct.localizedDescription, [numberFormatter stringFromNumber:adRemovalProduct.price], nil]
                                                       delegate:self cancelButtonTitle:@"No Thanks" otherButtonTitles:@"Purchase", nil];
        [alert show];
        [alert release];
        [numberFormatter release];
    }
    
    else
    {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"No Such Product"
                                                        message:@"The product you attempted to purchase is not yet available on the App Store. The developer apologizes for any inconvience. Your account was not charged."
                                                       delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
        [alert release];
    }
    
    [request autorelease];
}

Now, rather than crash, my app always says that no such product exists (the message I programmed it to display if there's an issue with the array size.)

I've attached a screenshot of what iTunes Connect shows for In-App purchases in my app.

attachment.php


It says "Ready to Submit" as the status, but when I click on it, it takes me to a page where I can edit details on it, but the "Submit for Review" button is grayed out, for no apparent reason.

So, can anyone help me out here? What am I doing wrong? I can't imagine Apple actually wants me to submit the binary at this point, because it doesn't make any sense to not be able to test the In-App Purchase feature of my app until after I submit it, does it?

Edit: Before anyone asks, the 512x512 is just a dummy image. I haven't actually made an icon for my app yet.
 

Attachments

  • In-App Purchase.png
    In-App Purchase.png
    117.2 KB · Views: 5,105
Last edited:

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,561
6,059
I think I've made some progress by following the detailed walkthrough here:

http://troybrant.net/blog/2010/01/in-app-purchases-a-full-walkthrough/

Since my prior post, I've:
1.) Prepared my app binary for upload, which entailed changing a few build settings and entitlements and stuff.
2.) Uploaded my app binary for review.
3.) Rejected my own binary.

This has caused the status of my In-App Purchase to become "Waiting for Review". After waiting about four hours, the empty array stopped being returned and I started getting back my localized product description that I'd posted on iTunes Connect.

So... to respond to the fact that the purchase button was pressed on my UIAlertView, I have this:

Code:
- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (buttonIndex != [alertView cancelButtonIndex])
    {
        [[SKPaymentQueue defaultQueue] addPayment:[SKPayment paymentWithProductIdentifier:@"findItFirstRemoveAds"]];
    }
}

And then the observer gets this:

Code:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
            case SKPaymentTransactionStateRestored:
                adsAreRemoved = YES;
                [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"adRemovalPurchased"];
                [[NSUserDefaults standardUserDefaults] synchronize];
                if (self.bannerIsVisible)
                {
                    [UIView beginAnimations:@"animateAdBannerOff" context:NULL];
                    adView.frame = CGRectOffset(adView.frame, 0, adView.frame.size.height);
                    [UIView commitAnimations];
                    self.bannerIsVisible = NO;
                }
                
                [UIView beginAnimations:@"animateEggDropBannerOff" context:NULL];
                eggDropBanner.frame = CGRectOffset(eggDropBanner.frame, 0, eggDropBanner.frame.size.height);
                [UIView commitAnimations];
                
                [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
                
                break;
            case SKPaymentTransactionStateFailed:
                if (transaction.error.code != SKErrorPaymentCancelled)
                {
                    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Purchase Failed"
                                                                    message:@"Your ad removal purchase has failed for an unknown reason. Your account was not charged."
                                                                   delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                    [alert show];
                    [alert release];
                }
                
                [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
                
                break;
            default:
                break;
        }
    }
}

Now... my issue is, I hit the purchase button, wait for about a minute, and then I get a message saying that the purchase failed.

Two questions:
1.) Why is my purchase failing?
2.) Why doesn't it ever ask for my account name / password? (I feel like if I knew the answer to #2 it might explain #1.)

Edit: I've now also added code to check each of the possible SKError codes... and it returns... none of them! It doesn't return Invalid Client, Payment Cancelled, Payment Invalid, Payment Not Allowed, or even Unknown Error! I therefore have some kind of mystical, super unknown error. Also, it doesn't report that the purchase has failed until 6 and a half minutes after the user told it to make a purchase.
 
Last edited:

Luke Redpath

macrumors 6502a
Nov 9, 2007
733
6
Colchester, UK
Have you signed out of your regular iTunes account on your test device? You should do this and when prompted in-app, sign in with a test user you have created in iTunes Connect (don't sign in with this user in Settings > Store beforehand).
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,561
6,059
Have you signed out of your regular iTunes account on your test device? You should do this and when prompted in-app, sign in with a test user you have created in iTunes Connect (don't sign in with this user in Settings > Store beforehand).

I had signed out, but when I double checked after reading your post, I found somehow I was still signed in. I signed out again. Checked my in-app purchase. It still fails, still for no known reason, not even SKErrorUnknown. I asked it to log the error code and it gave me -1001. Does anyone know the significance of that?
 

Luke Redpath

macrumors 6502a
Nov 9, 2007
733
6
Colchester, UK
I had signed out, but when I double checked after reading your post, I found somehow I was still signed in. I signed out again. Checked my in-app purchase. It still fails, still for no known reason, not even SKErrorUnknown. I asked it to log the error code and it gave me -1001. Does anyone know the significance of that?

FWIW, the sandbox environment seems to have been down for the past few hours. I've been having troubles here too (right as we're about to submit!).
 

ArtOfWarfare

macrumors G3
Original poster
Nov 26, 2007
9,561
6,059
FWIW, the sandbox environment seems to have been down for the past few hours. I've been having troubles here too (right as we're about to submit!).

Would it still be capable of giving me the details about the purchase? Would that prevent it from asking me to log in?

Edit: Evidently the answer is "yes" on both accounts, as now, without any changes to my code at all, it works pretty well. Although naming my product "Purchase Ad Removal" is kind of silly as now Apple's automatic confirmation says "Do you really want to buy one Purchase Ad Removal?"
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.