Dinesh
Dinesh

Reputation: 6532

InApp Purchase SKPaymentQueue finish Transaction doesn't work

i am working inapp purchase project in iOS sdk.i have prepared inapp purchase class for purchasing app from appstore with enable inner contents of the project.but, my problem is SKPaymentQueue doesn't finish working on my class.here's code of my inapp purchase class:

- (void)purchase {
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:@"com.test"];
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] addPayment:payment];

}

- (void)provideContent:(NSString *)productIdentifier {

    NSLog(@"Toggling flag for: %@", productIdentifier);
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:productIdentifier];
    [[NSUserDefaults standardUserDefaults] synchronize];
    //[_purchasedProducts addObject:productIdentifier];

    [[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchasedNotification object:productIdentifier];

}

- (void)completeTransaction:(SKPaymentTransaction *)transaction {

    NSLog(@"completeTransaction...");

    //[self recordTransaction: transaction];
    [self provideContent: transaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

- (void)restoreTransaction:(SKPaymentTransaction *)transaction {

    NSLog(@"restoreTransaction...");

    //[self recordTransaction: transaction];
    [self provideContent: transaction.originalTransaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

- (void)failedTransaction:(SKPaymentTransaction *)transaction {

    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
    }


    [[NSNotificationCenter defaultCenter] removeObserver:self name:kProductPurchaseFailedNotification object:transaction];


    [[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchaseFailedNotification object:transaction];


    //[[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationName" object:transaction];

    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}



- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {

    for (SKPaymentTransaction *transaction in transactions) {

        switch (transaction.transactionState) {

            case SKPaymentTransactionStatePurchasing:

                break;

            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                //[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

                break;

            case SKPaymentTransactionStateRestored:
                //[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                [self restoreTransaction:transaction];

                break;

            case SKPaymentTransactionStateFailed:
                if (transaction.error.code != SKErrorPaymentCancelled) {
                    NSLog(@"An error encounterd");
                }
                else {
                    NSLog(@"Cancelled!");
                }
                //[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

                [self failedTransaction:transaction];

                break;

        }

    }

}

- (void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

    [request release];
    [super dealloc];

}

that's line doesn't work on my class [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; transaction doesn't finish. and my another problem is nsnotificationcenter calls multiple times like if i click first time it's call only one time no problem,another time it's nsnotificationcenter calls 3 times.

Upvotes: 2

Views: 13430

Answers (3)

Kristoffer Stensaa
Kristoffer Stensaa

Reputation: 33

To fix this problem just add [[SKPaymentQueue defaultQueue]removeTransactionObserver:self]; right after [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

Upvotes: 3

Lova
Lova

Reputation: 134

You can do like this:

 - (void)buyProduct:(SKProduct *)product {

NSLog(@"Buying %@...", product.productIdentifier);
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];

 }


- (void)validateReceiptForTransaction:(SKPaymentTransaction *)transaction {
VerificationController * verifier = [VerificationController sharedInstance];
[verifier verifyPurchase:transaction completionHandler:^(BOOL success) {
    if (success) {
        NSLog(@"Successfully verified receipt!");
        [self provideContentForProductIdentifier:transaction.payment.productIdentifier];
    } else {
        NSLog(@"Failed to validate receipt.");
        [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

    }
}];
}


#pragma mark SKPaymentTransactionOBserver

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
    switch (transaction.transactionState) {
        case SKPaymentTransactionStatePurchasing:
            NSLog(@"Prossing.............");

            break;

        case SKPaymentTransactionStatePurchased:
        {

            [self completeTransaction:transaction];
            NSError* error;
            NSDictionary* jsonDict = [NSJSONSerialization
                                  JSONObjectWithData:transaction.transactionReceipt

                                  options:kNilOptions 
                                  error:&error];
            NSLog(@"JSON Receipt: %@",jsonDict);

            [[NSUserDefaults standardUserDefaults] setObject:jsonDict forKey:@"A"];
            NSLog(@"Purchase was a Success.....");
        }
            break;
        case SKPaymentTransactionStateFailed:

            [self failedTransaction:transaction];

            NSLog(@"Purchase cancelled");


            break;

        case SKPaymentTransactionStateRestored:

            [self restoreTransaction:transaction];

            default:

            break;
    }         
}
}



- (void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"completeTransaction...");

[self validateReceiptForTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}


- (void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"restoreTransaction...");

[self validateReceiptForTransaction:transaction];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}


 - (void)failedTransaction:(SKPaymentTransaction *)transaction {

NSLog(@"failedTransaction...");

[[SKPaymentQueue defaultQueue] finishTransaction: transaction];


if (transaction.error.code != SKErrorPaymentCancelled)
{
    NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
    MedPulseAppDelegate *appdelegate =( MedPulseAppDelegate *)[[UIApplication sharedApplication]delegate];
    [appdelegate hideLoading];
}

[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}



 - (void)provideContentForProductIdentifier:(NSString *)productIdentifier {

if ([productIdentifier isEqualToString:kMDPulseSubscriptionProductIdentifier]) {
    [self purchaseSubscriptionWithMonths:1];
 }

[[NSNotificationCenter defaultCenter] postNotificationName:IAPHelperProductPurchasedNotification object:productIdentifier userInfo:nil];

  }



  - (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
NSLog(@"%s","User Cancel.");



  }



 - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
 {
NSLog(@"Restore completed transactions finished.");
NSLog(@" Number of transactions in queue: %d", [[queue transactions] count]);
for (SKPaymentTransaction *trans in [queue transactions])
  {
    NSLog(@" transaction id %@ for product %@.", [trans transactionIdentifier], [[trans payment] productIdentifier]);
    NSLog(@" original transaction id: %@ for product %@.", [[trans originalTransaction] transactionIdentifier],
          [[[trans originalTransaction] payment]productIdentifier]);


    if ([[[trans payment] productIdentifier] isEqual: kMDPulseSubscriptionProductIdentifier]) {

        NSLog(@"Purchase Restored");

        // Do your stuff to unlock
    }
  }
 }


 - (void)restoreCompletedTransactions
 {
    NSLog(@"Restore Tapped in transaction process");
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
  }

Welcome!
If you have any doubt comment it down

Upvotes: 0

Dinesh
Dinesh

Reputation: 6532

i got solution your problem is addTransaction server duplicate to your issue,

try below code it's must working:

static bool hasAddObserver=NO;

- (void)purchase {
    if (!hasAddObserver) {//flag to fix this bug
        /*=====================================*/
        [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
        hasAddObserver=YES;
    }
    SKPayment *payment = [SKPayment paymentWithProductIdentifier:@"com.test"];
    //[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    [[SKPaymentQueue defaultQueue] addPayment:payment];

}


- (void)provideContent:(NSString *)productIdentifier {

    NSLog(@"Toggling flag for: %@", productIdentifier);
    [[NSUserDefaults standardUserDefaults] setBool:TRUE forKey:productIdentifier];
    [[NSUserDefaults standardUserDefaults] synchronize];
    //[_purchasedProducts addObject:productIdentifier];

    [[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchasedNotification object:productIdentifier];

}

- (void)completeTransaction:(SKPaymentTransaction *)transaction {

    NSLog(@"completeTransaction...");

    //[self recordTransaction: transaction];
    [self provideContent: transaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

- (void)restoreTransaction:(SKPaymentTransaction *)transaction {

    NSLog(@"restoreTransaction...");

    //[self recordTransaction: transaction];
    [self provideContent: transaction.originalTransaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

}

- (void)failedTransaction:(SKPaymentTransaction *)transaction {

    if (transaction.error.code != SKErrorPaymentCancelled)
    {
        NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
    }




    [[NSNotificationCenter defaultCenter] postNotificationName:kProductPurchaseFailedNotification object:transaction];


    //[[NSNotificationCenter defaultCenter] postNotificationName:@"NotificationName" object:transaction];

    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}



- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {

    for (SKPaymentTransaction *transaction in transactions) {

        switch (transaction.transactionState) {

            case SKPaymentTransactionStatePurchasing:

                break;

            case SKPaymentTransactionStatePurchased:
                //[self completeTransaction:transaction];
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

                break;

            case SKPaymentTransactionStateRestored:
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                //[self restoreTransaction:transaction];

                break;

            case SKPaymentTransactionStateFailed:
                if (transaction.error.code != SKErrorPaymentCancelled) {
                    NSLog(@"An error encounterd");
                }
                else {
                    NSLog(@"Cancelled!");
                }
                //[[SKPaymentQueue defaultQueue] finishTransaction:transaction];

                [self failedTransaction:transaction];

                break;

        }

    }

}

- (void)dealloc
{
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];

    [request release];
    [super dealloc];

}

Welcome!

Upvotes: 9

Related Questions