0
votes

I am trying to perform an in-app purchase, but it fails, and i cannot figure out why. The weird thing is, that it fetches the SKProduct just fine and can print all the details, but when i actually try to buy it, it just fails.

Now, since i know the product gets fetched and logs to the console, the problem is not with that. The problem lies when i try to actually purchase the fetched product, so here is the code for that:

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.

// Setup notifaction to handle the successfull payment
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(succeedPayment)
                                             name:@"kInAppPurchaseManagerTransactionSucceededNotification"
                                           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(failedPayment)
                                             name:@"kInAppPurchaseManagerTransactionFailedNotification"
                                           object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(cancelPayment)
                                             name:@"userCancel"
                                           object:nil];
}

- (IBAction)purchase10Crystals:(id)sender {
    InAppPurchaseManager *p = [InAppPurchaseManager IAPManager];
    if ([p canMakePurchases]) {
        [p purchaseGoldCoins:10];
        NSLog(@"Buying 10 crystals");
    }
}

So there i have the View Controller listen to notifications regarding payment, and to actually make a payment. Here is what happens inside the InAppPurchaseManager:

SKPayment *payment = [SKPayment paymentWithProduct:gold10];
    [[SKPaymentQueue defaultQueue] addPayment:payment];

Now the purchase is sent to the store. The manager waits for a respond, and these are the options:

    //
// removes the transaction from the queue and posts a notification with the transaction result
//
- (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)
    {
        // send out a notification that we’ve finished the transaction
        [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionSucceededNotification object:self userInfo:userInfo];
        NSLog(@"Success transaction!");
    }
    else
    {
        // send out a notification for the failed transaction
        [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];
    }
}

//
// called when the transaction was successful
//
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
    [self recordTransaction:transaction];
    [self provideContent:transaction.payment.productIdentifier];
    [self finishTransaction:transaction wasSuccessful:YES];

}

//
// 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 a transaction has failed
//
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        // error!
        NSLog(@"Failed: %li", (long)transaction.error);
        [self finishTransaction:transaction wasSuccessful:NO];
    }
    else
    {
        // this is fine, the user just cancelled, so don’t notify
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"userCancel" object:self userInfo:nil];
    }
}

The method that gets called is failedTransaction. I have no idea why. The sandbox account is working because it can play on game center for testing. The product gets fetched because it prints it all out. But when i try to purchase, it just fails, and doesn't tell me why. The code that gets logged out is just a lot of numbers.

Hope anyone can help me. Best Regards /JBJ

EDIT This is how i fetch the SKProducts.

  1. First i call this to load it up

    - (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 request10GoldData];
    

    }

  2. Fetch the Product from the store

    -(void) request10GoldData
    

    { NSSet *productIdentifiers = [NSSet setWithObject:@"10crystals" ]; productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers]; productsRequest.delegate = self; [productsRequest start]; }

  3. Print it out to verify it was fetched

    - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
    

    { // Make a new SKProduct, identify which product it is, and add to proper instance variable

    NSArray *products = response.products;
    SKProduct *theProduct = [products count] == 1 ? [products objectAtIndex:0] : nil;
    if (theProduct)
    {
        // Identify the product and assign to instance variable SKProducts
        if ([theProduct.productIdentifier isEqualToString:@"10crystals"]) {
            gold10 = theProduct;
        }
    
        // Debugging
        NSLog(@"Product title: %@" , theProduct.localizedTitle);
        NSLog(@"Product description: %@" , theProduct.localizedDescription);
        NSLog(@"Product price: %@" , theProduct.price);
        NSLog(@"Product id: %@" , theProduct.productIdentifier);
    }
    
    for (NSString *invalidProductId in response.invalidProductIdentifiers)
    {
        NSLog(@"Invalid product id: %@" , invalidProductId);
    }
    
    
    [[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
    

    }

This works, and in the above NSLog statements it prints out exactly what i created in iTunes connect.

1
have you added the product id(s) to your application on iTunes Connect site?holex
yes i have, and it can fetch the data without issues. It just can't complete the transaction.J.B.J.
tell me, please, how you have added them to your application. because there are two steps: 1. defining a product and 2. adding it to your application. I assume you have done both essential steps, right?holex
I edited the post to show how i fetch the products. It can print out the product information using NSLog so i know it fetched the right one. That is what stumps me. Because it seems to be working, and it can identify the products to get, but it can't complete the purchase.J.B.J.
I narrowed it down to the fact that it says "Cannot connect to iTunes Store"??J.B.J.

1 Answers

1
votes

Alright what a bummer. I discovered it was as simple as logging out of my actual account when testing this -.-' I didn't find anyone else having this problem because i didn't print out the error of the transaction.

So for anyone else having issues, try this: 1. Log the error description like this:

    - (void)failedTransaction:(SKPaymentTransaction *)transaction
{
    // Log the error
    NSLog(@"%@", [transaction.error localizedDescription]);

    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        // error!
        [self finishTransaction:transaction wasSuccessful:NO];
    }
    else
    {
        // this is fine, the user just cancelled, so don’t notify
        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"userCancel" object:self userInfo:nil];
    }
}

If the error says something about "not being able to connect to iTunes store" -> then go to settings on your test device, and sign out of your actual account so you can log into your test account!

This solved it for me. Thanks for trying to help. Next time i will be sure to log the error out first.