I am implementing in-app purchase in a Mac app using the following code.
@implementation AppStoreObserver
-(id) init {
self = [super init];
if (self) {
_products = [[NSMutableArray alloc] init];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
}
return self;
}
-(void)dealloc {
[_products release];
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[super dealloc];
}
#pragma mark - Query products
-(void)loadStoreForProducts:(NSArray *)productIds {
SKProductsRequest *productRequest = [[[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithArray:productIds]] autorelease];
productRequest.delegate = self;
[productRequest start];
}
#pragma mark - Product Delegate
//Got product info
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
[_products removeAllObjects];
for (SKProduct *_product in response.products) {
[_products addObject:_product];
}
[[NSNotificationCenter defaultCenter] postNotificationName:kNotificationStoreManagerProductsReceivedInvalid
object:nil
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:response.invalidProductIdentifiers, @"invalidProductIdentifiers", _products, @"products", nil]];
}
#pragma mark - Purchase
-(void) triggerPurchase:(SKProduct *) product {
[[SKPaymentQueue defaultQueue] addPayment:[SKPayment paymentWithProduct:product]];
}
- (BOOL)canMakePurchases
{
return [SKPaymentQueue canMakePayments];
}
- (void)purchaseProduct:(NSString *)productId
{
if([self canMakePurchases]){
for (SKProduct *_product in _products) {
if ([_product.productIdentifier isEqualToString:productId]) {
[self triggerPurchase:_product];
break;
}
}
}
}
#pragma mark - Payment Queue observers
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction* transaction in transactions)
{
//NSLog(@"%d", transaction.transactionState);
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchasing:
NSLog(@"Purchasing");
break;
case SKPaymentTransactionStatePurchased:
NSLog(@"Purchased");
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed:
NSLog(@"Error: %@", transaction.error);
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored:
NSLog(@"Restored");
[self restoreTransaction:transaction];
break;
default:
break;
}
}
}
#pragma mark - Custom handlers
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
NSLog(@"restore transaction %@ %@",transaction.transactionIdentifier , transaction.originalTransaction);
[self finishTransaction:transaction wasSuccessful:YES];
}
-(void) restoreCompletedTransactions {
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
[self finishTransaction:transaction wasSuccessful:YES];
}
- (void) failedTransaction: (SKPaymentTransaction *)transaction
{
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];
return;
}
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert addButtonWithTitle:@"OK"];
[alert setMessageText:@"Alert"];
[alert setInformativeText:@"In-App Purchase Failed"];
[alert setAlertStyle:NSWarningAlertStyle];
[alert runModal];
}
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
//NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil];
if (wasSuccessful) {
// send out a notification that we’ve finished the transaction
} else {
NSLog(@"user cancelled");
}
}
@end
I am able to retrieve SKProduct successfully but as soon as I purchase a product using a test account the process halts without failing. The SKPaymentTransactionStatePurchasing state is reached but nothing happens afterwards. Even the purchase confirmation dialog is not presented.
Once I stop and re-run the app the last transaction is completed successfully but as soon as I try to make another transaction the same thing happens. I have spent several days trying to identify the cause without success. I hope someone here is able to identify the problem. Thanks for your time.