I'm learning how to use in-app purchases and recently implemented it in my first app. To test it out on my phone, I created two test accounts and bought one item with each account, both different. When I delete the app and reopen it, it attempts to restore the data of both accounts and provides the upgrades regardless of whether I sign in or not. (paymentQueue: updatedTransactions:
is being called and passing a transaction in the state SKPaymentTransactionStateRestored
)
Could this be solved by validating the receipts? I've looked into it but have been putting it off since it looks a little daunting. Hopefully this is only a problem when testing multiple accounts.
For reference, I followed this guide but did the Transaction Observer methods in the App Delegate and the Product Request in a custom class. I also never reorded the transactions because apparently that's outdated. http://troybrant.net/blog/2010/01/in-app-purchases-a-full-walkthrough/
edit: I was just doing some testing and found that there are 0 transactions on the queue on startup right after being added as an observer but after the uidatedTransactions gets called there are 3.
My code for reference (Sorry if it's bad I'm still new):
#pragma mark - SKPaymentTransactionObserver
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
NSLog(@"Transactions Count: %d", [[[SKPaymentQueue defaultQueue] transactions] count]);
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchased:
[self comleteTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction:transaction];
break;
default:
break;
}
}
}
//case methods
- (void)comleteTransaction:(SKPaymentTransaction *)transaction
{
[self provideContent:transaction.payment.productIdentifier];
[self finishTransaction:transaction wasSuccessful:YES];
}
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
[self provideContent:transaction.originalTransaction.payment.productIdentifier];
[self finishTransaction:transaction.originalTransaction wasSuccessful:YES];
}
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
if (transaction.error.code != SKErrorPaymentCancelled)
[self finishTransaction:transaction wasSuccessful:NO]; //serious error
else
[[SKPaymentQueue defaultQueue] finishTransaction:transaction]; //user cancelled
}
//action methods
- (void)provideContent:(NSString *)productID
{
//validate app receipt?
if ([productID isEqualToString:UNLOCK_EVERYTHING_ID])
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:UNLOCK_EVERYTHING_PURCHASED_KEY];
else if ([productID isEqualToString:REMOVE_ADS_ID])
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:REMOVE_ADS_PURCHASED_KEY];
else if ([productID isEqualToString:BASIC_PACK_ID])
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:BASIC_PACK_PURCHASED_KEY];
else if ([productID isEqualToString:CLOTHING_PACK_ID])
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:CLOTHING_PACK_PURCHASED_KEY];
else if ([productID isEqualToString:FOOD_PACK_ID])
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:FOOD_PACK_PURCHASED_KEY];
else if ([productID isEqualToString:ORIGINAL_PACK_ID])
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:ORIGINAL_PACK_PURCHASED_KEY];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//post notification that transaction finished
if (wasSuccessful) {
[[NSNotificationCenter defaultCenter] postNotificationName:TRANSACTION_SUCCESSFUL object:nil];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:TRANSACTION_UNSUCCESSFUL object:nil];
}
}