Question

I've taken a look around google, and pretty much every single stackoverflow question about adding in-app purchases, yet none of them seem to work. When I try to make a purchase on my app, Everything works fine, the products are available and everything, yet the alert view about purchasing never shows up. Heres all my code for the IAP:

- (IBAction)tapsRemoveAdsButton{
NSLog(@"User taps remove ads button");
[self tapsRemoveAds];
}

- (void)tapsRemoveAds{
NSLog(@"User requests to remove ads");

if([SKPaymentQueue canMakePayments]){
    NSLog(@"User can make payments");

    SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:kRemoveAdsProductIdentifier]];
    productsRequest.delegate = self;
    [productsRequest start];

}
else{
    NSLog(@"User cannot make payments due to parental controls");
}
}

- (IBAction)purchase{
SKProduct *removeAdsProductID = (SKProduct *)kRemoveAdsProductIdentifier;
SKPayment *payment = [SKPayment paymentWithProduct:(SKProduct *)kRemoveAdsProductIdentifier];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[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 Avalable!");
    //[self sloganizeWord];
}
else if(!validProduct){
    NSLog(@"No products avalable");
}
}

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for(SKPaymentTransaction *transaction in transactions){
    switch (transaction.transactionState){
        case SKPaymentTransactionStatePurchasing: NSLog(@"Transaction state -> Purchasing");
            break;
        case SKPaymentTransactionStatePurchased: [self doRemoveAds];
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
             NSLog(@"Transaction state -> Purchased");
            break;
        case SKPaymentTransactionStateRestored:
             NSLog(@"Transaction state -> Restored");
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            break;
        case SKPaymentTransactionStateFailed:
            if(transaction.error.code != SKErrorPaymentCancelled){
                NSLog(@"Transaction state -> Cancelled");
            }
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            break;
        }
    }
}


- (void)doRemoveAds{
areAdsRemoved = YES;
[[NSUserDefaults standardUserDefaults] setBool:areAdsRemoved forKey:@"areAdsRemoved"];
[[NSUserDefaults standardUserDefaults] synchronize];
}

If I'm doing this correctly the alert view should show up in the method "paymentQueue" all IN the console I get:

user taps remove ads button
user requests to remove ads
user can make payments
products available!

everything up until the paymentQueue method, where it also should log

transaction state -> purchasing

and others, I already have the IAP set up in iTunes Connect, and the ID for the IAP is correct. (otherwise it wouldn't log products available) I'm using a non-jailbroken device on iOS7 and I have all of the provisioning profiles set up (or at least I think, because I already submitted the app to the app store with ads) Again, I have looked at some of the other questions, yet none of them seem to offer any help to me. Thanks in advance to anyone and everyone who helps :)

Was it helpful?

Solution

This not ok: SKProduct *removeAdsProductID = (SKProduct *)kRemoveAdsProductIdentifier; - you can't use a NSString* instead of a SKProduct*.

You should instead use validProduct from - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response.

You only need 1 button/action, the tapRemoveAds, which should be initiating the purchase (no need for the purchase IBAction).

You need to take hold of an actual SKProduct*:

- (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 Avalable!");

        // initiate the actual purchase
        [self purchase:validProduct];
    }
    else if(!validProduct){
        NSLog(@"No products avalable");
    }
}

-(void)purchase:(SKProduct *)product{
    SKPayment *payment = [SKPayment paymentWithProduct:product];
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] addPayment:payment];
}

A better solution would be to retrieve the list of valid products in a previous step (e.g: when the app starts), and only enable the upgrade button when the SKProduct * object for it is available.

There are other issues as well, like not handling the restore (should be handled similarly as in SKPaymentTransactionStatePurchasing case). I suggest you have a look over In-App Purchase Programming Guide for a better understanding.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top