0

私は Spritekit で作業しており、ゲームで SKPayments を有効にして、ユーザーが購入すると 5 つのライフを与えようとしています。しかし、アプリを実行して購入しようとするたびに、SKProduct FiveLives が nil であるというエラーが表示され続けます。エラーが発生し続けるコードと行は以下のとおりです。誰か助けてくれませんか?

self.product1ID = @"com.retrogames.5Lives";

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

[self getProduct1ID:self];

SKPayment *payment = [SKPayment paymentWithProduct:_FiveLives];
ERROR LINE  [[SKPaymentQueue defaultQueue] addPayment:payment];

}

私のクラスの残りはここにあります

StoreViewController.h

#import <UIKit/UIKit.h>
#import <StoreKit/StoreKit.h>    
@interface StoreViewController : UIViewController <SKPaymentTransactionObserver, SKProductsRequestDelegate>{
SKProductsRequest *productsRequest;
}



@property (strong, nonatomic) SKProduct *FiveLives;
@property (strong, nonatomic) NSString *product1ID;

- (IBAction)_5Lives:(id)sender;

-(void)getProduct1ID:(UIViewController *)viewcontroller;

@end

StoreViewController.M

  #import "StoreViewController.h"

 @interface StoreViewController ()

 @end

 @implementation StoreViewController

 - (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)getProduct1ID:(UIViewController *)viewcontroller{

  if ([SKPaymentQueue canMakePayments]) {
    SKProductsRequest *request = [[SKProductsRequest alloc]initWithProductIdentifiers:[NSSet setWithObject:self.product1ID]];
    request.delegate = self;
    [request start];
    }
   else{
       UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Sorry purchase was unsuccessful" message:@"Please enable in app purchases in your settings" delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
    [alert show];

   }


  }

  #pragma mark _
  #pragma mark SKProductsRequestDelegate

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

   NSArray *Products = response.products;

   if (Products.count != 0) {

    _FiveLives = Products[0];

    }

   Products = response.invalidProductIdentifiers;

    for (SKProduct *FiveLives in Products) {
      NSLog(@"Product Not Found : %@", FiveLives);
    }

   }

 - (IBAction)_5Lives:(id)sender {
self.product1ID = @"com.retrogames.5Lives";

[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

[self getProduct1ID:self];

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

 }

 - (IBAction)RestorePurchases:(id)sender{
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue]restoreCompletedTransactions];
 }

 -(void)add5Lives{
NSLog(@"BUY5LIVES");
GameLives = GameLives + 5;
    [[NSUserDefaults standardUserDefaults] setInteger:GameLives forKey:@"Key"];

   }

  -(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
for (SKPaymentTransaction *transaction in transactions) {

    switch (transaction.transactionState) {
        case SKPaymentTransactionStatePurchased:[self add5Lives];{

            NSLog(@"TRANSACTION SUCCESSFUL");
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            break;
        }
        case SKPaymentTransactionStateFailed:NSLog(@"TRANSACTION FAILED");{
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
            UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Payment was unsuccessful" message:@"Payment was unable to be processed." delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
            [alert show];
        }

            break;

            default:
            break;
    }
    }
}

チュートリアルを使用した後の新しいコード

購入ライブ

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

IAPヘルパー

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

命を買う

#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
4

1 に答える 1

0

問題はここにあります:

[self getProduct1ID:self];

SKPayment *payment = [SKPayment paymentWithProduct:_FiveLives];

getProduct1IDストアからすべての商品を受け取るリクエストを発行します。ただし、このリクエストはノンブロッキングです。リクエストが完了するまでに、すでに を呼び出していることを意味しますpaymentWithProduct。そして、この時点_FiveLivesではまだ有効な製品と設定されていませんでしたnil

私がお勧めするgetProduct1IDのは、アプリケーションの START で呼び出し (アプリのデリゲート メソッドで行いますapplication:didFinishLaunchingWithOptions:)、後で使用できるメンバー変数に製品を格納することです。

次に、ユーザーが購入ボタンをクリックすると、製品インスタンスを使用して購入します。

また、こちらを見て、IAP のフローがどのようにコミットされているかを確認することをお勧めします。私が従った素晴らしいチュートリアルで、完全に機能します。

于 2015-06-03T15:33:30.770 に答える