SKProduct keeps returning nil. SKPayment Transaction is not working

517 views Asked by At

I am working in Spritekit and I am trying to enable SKPayments in my game to give the user the product once they make their purchase. I used the Ray Wenderlich Tutorial to assist me with this but since the tutorial is using tableviews and my game is not using table views I wrote the code just using UIViewStoryBoards. When I run the app and try to make a purchase I keep getting an error that my SKProduct is nil. The code and the line I keep getting the error on is below. Can somebody please help me?

PURCHASELIVES

PurchaseLives.m

+ (PurchaseLives *)sharedInstance {
static dispatch_once_t once;
static PurchaseLives * sharedInstance;
dispatch_once(&once, ^{
NSSet * productIdentifiers = [NSSet setWithObjects:
                              @"com.retrogames.5Lives",
nil];
sharedInstance = [[self alloc] initWithProductIdentifiers:productIdentifiers];
});
    return sharedInstance;
}

@end

IAPHelper

 IAPHelper.m
NSString *const IAPHelperProductPurchasedNotification = @"IAPHelperProductPurchasedNotification";
@interface IAPHelper () <SKProductsRequestDelegate, SKPaymentTransactionObserver>
@end

@implementation IAPHelper {
// 3
SKProductsRequest * _productsRequest;
// 4
RequestProductsCompletionHandler _completionHandler;
NSSet * _productIdentifiers;
NSMutableSet * _purchasedProductIdentifiers;
}


- (id)initWithProductIdentifiers:(NSSet *)productIdentifiers {

if ((self = [super init])) {

 // Store product identifiers
 _productIdentifiers = productIdentifiers;

// Check for previously purchased products
_purchasedProductIdentifiers = [NSMutableSet set];
for (NSString * productIdentifier in _productIdentifiers) {
    BOOL productPurchased = [[NSUserDefaults standardUserDefaults] boolForKey:productIdentifier];
    if (productPurchased) {
        [_purchasedProductIdentifiers addObject:productIdentifier];
        NSLog(@"Previously purchased: %@", productIdentifier);
    } else {
        NSLog(@"Not purchased: %@", productIdentifier);
    }


}
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
   }
     return self;
}

    - (void)requestProductsWithCompletionHandler:(RequestProductsCompletionHandler)completionHandler {

// 1
 _completionHandler = [completionHandler copy];

// 2
 _productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:_productIdentifiers];
 _productsRequest.delegate = self;
 [_productsRequest start];

  }

#pragma mark - SKProductsRequestDelegate

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


 NSLog(@"Loaded list of products...");
 _productsRequest = nil;

 NSArray * skProducts = response.products;
 for (SKProduct * skProduct in skProducts) {
  NSLog(@"Found product: %@ %@ %0.2f",
      skProduct.productIdentifier,
      skProduct.localizedTitle,
      skProduct.price.floatValue);

   FiveLives = skProducts[0];
      NSLog(@"Products = %@",skProducts);

 }

_completionHandler(YES, skProducts);
_completionHandler = nil;

  }

  - (void)request:(SKRequest *)request didFailWithError:(NSError *)error {

   NSLog(@"Failed to load list of products.");
  _productsRequest = nil;

 _completionHandler(NO, nil);
 _completionHandler = nil;

    }

 - (BOOL)productPurchased:(NSString *)productIdentifier {
return [_purchasedProductIdentifiers containsObject:productIdentifier];
    }

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

  NSLog(@"Buying %@...", FiveLives.productIdentifier);

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

  }



  - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
 {
        for (SKPaymentTransaction * transaction in transactions) {
        switch (transaction.transactionState)
  {
        case SKPaymentTransactionStatePurchased:
        [self completeTransaction:transaction];
        break;
        case SKPaymentTransactionStateFailed:
        [self failedTransaction:transaction];
        break;
        case SKPaymentTransactionStateRestored:
        [self restoreTransaction:transaction];
        default:
        break;
      }
     } 
    }



 // Add new method
- (void)provideContentForProductIdentifier:(NSString *)productIdentifier {

[_purchasedProductIdentifiers addObject:productIdentifier];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:productIdentifier];
[[NSUserDefaults standardUserDefaults] synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:IAPHelperProductPurchasedNotification object:productIdentifier userInfo:nil];

 }

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

    [self provideContentForProductIdentifier:transaction.payment.productIdentifier];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

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

     [self provideContentForProductIdentifier:transaction.originalTransaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
 }

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

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

   [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
  }


  @end

BUYLIVES

  #import "BuyLivesViewController.h"
  #import "PurchaseLives.h"
  #import "IAP Helper.h"
  @interface BuyLivesViewController (){
  NSArray *_products;
  }

 @end

 @implementation BuyLivesViewController

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

  - (void)didReceiveMemoryWarning {
  [super didReceiveMemoryWarning];
 // Dispose of any resources that can be recreated.
 }
 - (void)viewWillAppear:(BOOL)animated {
     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(productPurchased:) name:IAPHelperProductPurchasedNotification object:nil];
   }

- (void)viewWillDisappear:(BOOL)animated {
 [[NSNotificationCenter defaultCenter] removeObserver:self];
  }
  - (IBAction)Buy5Lives:(id)sender {



  [[PurchaseLives sharedInstance] buyProduct:FiveLives];
  }


 - (void)productPurchased:(NSNotification *)notification {

   NSString * productIdentifier = notification.object;
   [_products enumerateObjectsUsingBlock:^(SKProduct * product, NSUInteger idx, BOOL *stop) {
       if ([product.productIdentifier isEqualToString:productIdentifier]) {
    GameLives = GameLives + 5;

     }
  }];

 }
  @end
0

There are 0 answers