我在Spritekit工作,我试图在我的游戏中启用SKPayments,一旦他们购买就给用户5个生命。但每次我运行应用程序并尝试购买时,我都会收到错误,我的SKProduct FiveLives是零。我不断得到错误的代码和行在下面。有人可以帮帮我吗?
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
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 :(得分:0)
问题在于:
[self getProduct1ID:self];
SKPayment *payment = [SKPayment paymentWithProduct:_FiveLives];
getProduct1ID
发出从商店接收所有商品的请求。但是这个请求是非阻塞的。意味着在请求完成时您已经在调用paymentWithProduct
。在此时间_FiveLives
尚未使用有效产品进行设置,它将为nil
。
我建议您做的是在应用程序的START处调用getProduct1ID
(我在应用程序委托方法application:didFinishLaunchingWithOptions:
中执行此操作)并将您的产品存储在成员变量中你以后可以用。
然后,当用户点击购买按钮时,只需使用产品实例进行购买。
我还建议您查看here,看看如何提交IAP流程。我遵循的伟大教程,它完美无缺。