在调用canMakePayments后,应用内购买会冻结并崩溃我的应用

时间:2015-01-03 21:58:05

标签: objective-c in-app-purchase sprite-kit selector

业余人士。按下“购买”按钮时,代码效果很好(我使用断点来挑选有问题的行,见下文),直到调用canMakePayments为止。处理IAP的场景包括GamesceneInAppManagerInAppObserverORPurchaseProduct;所有相关代码如下。

我的应用在break之后崩溃了。一切正常,直到break行。这是在InAppManager.m内。向下滚动以查看InAppManager.m中的所有代码。应用程序崩溃后,IAP类型继续显示alertView要求我购买。点击购买后,alertView消失,应用程序不响应任何触摸。当我关闭应用程序并打开它时,它表明我已经购买了产品,一切都运行良好。我分享了所有信息,提前致谢。

有人可以告诉我指示。

-(void) buyFeature:(NSString*) featureID {

    if ([SKPaymentQueue canMakePayments]) {
        NSLog(@"Can make payments");
        SKProduct* selectedProduct;

        for (int i=0; i < [purchaseableProducts count]; i++) {
            selectedProduct = [purchaseableProducts objectAtIndex:i];

            if ([[selectedProduct productIdentifier] isEqualToString:featureID]) {

                // if we found a SKProduct in the purchaseableProducts array with the same ID as the one we want to buy, we proceed by putting it in the payment queue.

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

                NSLog(@"Proceeding by putting the product in the payment queue");

                break;

            }
            else {

                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Sorry" message:@"You can't purchase from the App Store" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                [alert show];

            }

        }
    }
}

这是崩溃后在控制台中的样子

2015-01-03 20:51:09.244 My App Name[1785:95544] Proceeding by putting the product in the payment queue
2015-01-03 20:51:10.369 My App Name[1785:95544] -[ORPurchaseProduct setGamePaused:]: unrecognized selector sent to instance 0x7fcf9b417ce0
2015-01-03 20:51:10.389 My App Name[1785:95544] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ORPurchaseProduct setGamePaused:]: unrecognized selector sent to instance 0x7fcf9b417ce0'
*** First throw call stack:
(
    0   CoreFoundation                      0x000000010ed55f35 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x000000010e697bb7 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010ed5d04d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x000000010ecb527c ___forwarding___ + 988
    4   CoreFoundation                      0x000000010ecb4e18 _CF_forwarding_prep_0 + 120
    5   My App Name                         0x000000010dcd3d88 -[AppDelegate applicationWillResignActive:] + 216
    6   UIKit                               0x000000010f535d96 -[UIApplication _deactivateForReason:notify:] + 338
    7   CoreFoundation                      0x000000010ed25cec __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    8   CoreFoundation                      0x000000010ecdf72e ____CFXNotificationPostToken_block_invoke + 142
    9   CoreFoundation                      0x000000010ec8b53c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    10  CoreFoundation                      0x000000010ec81285 __CFRunLoopDoBlocks + 341
    11  CoreFoundation                      0x000000010ec80a67 __CFRunLoopRun + 887
    12  CoreFoundation                      0x000000010ec80486 CFRunLoopRunSpecific + 470
    13  GraphicsServices                    0x0000000110dee9f0 GSEventRunModal + 161
    14  UIKit                               0x000000010f53b420 UIApplicationMain + 1282
    15  My App Name                         0x000000010dcfaf03 main + 115
    16  libdyld.dylib                       0x00000001111da145 start + 1
    17  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb) 

这就是InAppPurchase.m中的整个代码的样子

@interface InAppManager () {

    NSMutableArray* purchaseableProducts; // an array of possible products to purchase
    NSUserDefaults* defaults; // store a bool variable marking products that have been unlocked
    bool product1WasPurchased; // YES or NO

    InAppObserver* theObserver;

}

@end

@implementation InAppManager

static NSString* productID1 = @"MyProduct";


static InAppManager* sharedManager = nil;

+(InAppManager*) sharedManager {

    if(sharedManager == nil) {

        sharedManager = [[InAppManager alloc] init];

    }

    return sharedManager;
}

-(id) init {

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

        //do initialization

        sharedManager = self;
        defaults = [NSUserDefaults standardUserDefaults]; 
        product1WasPurchased = [defaults boolForKey:productID1]; 


        purchaseableProducts = [[NSMutableArray alloc] init];
        [self requestProductData]; 

        theObserver = [[InAppObserver alloc] init];
        [[SKPaymentQueue defaultQueue] addTransactionObserver:theObserver];
    }

    return self;

}

-(void) requestProductData {

    SKProductsRequest* request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:productID1, nil]]; 

    request.delegate = self;
    [request start];
}


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



    NSArray* skProducts = response.products; 

    if ( [skProducts count] != 0 && [purchaseableProducts count] == 0) {

        for (int i = 0; i < [skProducts count]; i++) {

            [purchaseableProducts addObject:[skProducts objectAtIndex:i]];
            SKProduct* product = [purchaseableProducts objectAtIndex:i];

            NSLog(@"Feature: %@, Cost: %f, ID: %@", [product localizedTitle], [[product price] doubleValue], [product productIdentifier] );

        }

    }

    NSLog(@" We found %lu In-App Purchases in iTunes Connect", (unsigned long)[purchaseableProducts count]);

}


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

    NSString* failMessage = [NSString stringWithFormat:@"Reason: %@, You can try: %@", [transaction.error localizedFailureReason], [transaction.error localizedRecoverySuggestion]  ];

    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Unable to complete your purchase" message:failMessage delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alert show];


}
-(void) provideContent:(NSString*) productIdentifier{


    NSNotificationCenter* notification = [NSNotificationCenter defaultCenter]; 

    if ( [productIdentifier isEqualToString:productID1]) {
        product1WasPurchased = YES;
        [defaults setBool:YES forKey:productID1];
        [notification postNotificationName:@"feature1Purchased" object:nil];

        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Thank you!" message:@"You have purchased MyProduct" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];

    }
    else {
        NSLog(@"Error: Something happened!");
    }


}


-(void) buyFeature1 {

    [self buyFeature:productID1];

}

-(void) buyFeature:(NSString*) featureID {

    if ([SKPaymentQueue canMakePayments]) {
        NSLog(@"Can make payments");
        SKProduct* selectedProduct;

        for (int i=0; i < [purchaseableProducts count]; i++) {
            selectedProduct = [purchaseableProducts objectAtIndex:i];

            if ([[selectedProduct productIdentifier] isEqualToString:featureID]) {

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

                NSLog(@"Proceeding by putting the product in the payment queue");

                break;

            }
            else {

                UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Oh no" message:@"You can't purchase from the App Store" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
                [alert show];

            }

        }
    }
}

-(bool) isFeature1PurchasedAlready {

    return product1WasPurchased;
}


-(void) restoreCompletedTransactions{

    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

}

这是InAppObserver.m

中整个代码的样子
#import "InAppObserver.h"
#import "InAppManager.h"  

@implementation InAppObserver

-(void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {

    NSLog(@"Payment queue options");

    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];
                break;

            default:
                break;
        }

    }

}

-(void)failedTransaction:(SKPaymentTransaction*) transaction {
    NSLog(@"Transaction Failed");

    //if the error was anything other than the user cancelling it

    if (transaction.error.code != SKErrorPaymentCancelled) {

        [[InAppManager sharedManager] failedTransaction:transaction];

        NSLog(@"%@", [transaction.error localizedDescription]);

    }

    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

}

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

    //when we pass the transaction back to the sharedManager it has the product ID

    [[InAppManager sharedManager] provideContent:transaction.payment.productIdentifier];

    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

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

     [[InAppManager sharedManager] provideContent:transaction.originalTransaction.payment.productIdentifier];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

@end

我在GameScene中有这些行,一切都开始了,我只选择了相关的代码。

-(void)didMoveToView:(SKView *)view {
    /* Setup your scene here */

[InAppManager sharedManager];

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(unlockProduct1) name:@"feature1Purchased" object:nil];
}

-(void) unlockProduct1 {

    NSLog(@"this class knows we purchased the product!");

}

我在ORPurchaseProduct.m中有这些行。在这里,我有购买按钮,它检查产品是否已经购买。我从GameScene过渡到这个。

-(void)didMoveToView:(SKView *)view
{
[InAppManager sharedManager];

if ( [[InAppManager sharedManager] isFeature1PurchasedAlready] == NO) {
    NSLog(@" product was not bought yet");
    [self createBuyButton:@"BUY"];

} else {
    NSLog(@" product was bought");
    [self createBuyButton:alreadyBoughtMessage];
}
}

-(void) createBuyButton:(NSString*) theMessage {

    UIFont* theFont = [UIFont fontWithName:@"BUY" size:18];

    thePurchaseButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];

    if( [theMessage isEqualToString:alreadyBoughtMessage]) {

        [thePurchaseButton addTarget:self action:@selector(doNothing) forControlEvents:UIControlEventTouchUpInside];

        NSLog(@"Already bought message: we are here");

    } else {

        [thePurchaseButton addTarget:[InAppManager sharedManager] action:@selector(buyFeature1) forControlEvents:UIControlEventTouchUpInside];
    }

    [thePurchaseButton.titleLabel setFont:theFont];
    [thePurchaseButton setTitle:theMessage forState:UIControlStateNormal];
    [thePurchaseButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
    [thePurchaseButton setBackgroundColor:[UIColor blackColor]];
    thePurchaseButton.frame = CGRectMake(80, 380, 160, 30);
    [self.view addSubview:thePurchaseButton];      
}

-(void)doNothing
{
    NSLog(@"Nothing to be done because the product is already bought!");
}

1 个答案:

答案 0 :(得分:0)

我注释掉了这行代码,一切顺利,它出现在AppDelegate的applicationWillResignActive方法中。谢谢你们。

SKView *view = (SKView *)self.window.rootViewController.view;
((GameScene *)view.scene).gamePaused = YES;