-2

我最近向 App Store 提交了一个应用程序。客户在尝试购买应用内购买(或任何与此相关的)时报告了崩溃;但不幸的是,我无法在开发版本中复制它。这是崩溃日志:

 https://www.dropbox.com/s/ml9xvb1pk7hxtiu/memejump.crash

使用 xcode 5. 编译器可能有问题吗?

编辑:

是的,所有 Iap 都已提交,我想我知道为什么会出现崩溃。我有一个庞大、复杂且不可靠的 if 语句系列,检查请求是为了购买还是只是为了获取价格,以便不会弹出警报视图。一定有什么问题,但我找不到它......有谁知道一种方法来检查它是购买还是只是请求获得展示价格?我很快就会用象征性的崩溃来摆出代码。

#import "StoreViewController.h"

int internetActive;

BOOL forButtonsAndLabels;
BOOL forPurchase;
BOOL fakePurchase;

@interface StoreViewController ()

@end

@implementation StoreViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    //for internet test
    // check for internet connection
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(checkNetworkStatus:) name:kReachabilityChangedNotification object:nil];

    internetReachable = [Reachability reachabilityForInternetConnection];
    [internetReachable startNotifier];

    // check if a pathway to a random host exists
    hostReachable = [Reachability reachabilityWithHostName: @"www.apple.com"];
    [hostReachable startNotifier];

}


- (void)setButtonsAndLabelsForExtraCoins {

    if (internetActive == YES) {

        forButtonsAndLabels = YES;

        SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObjects:@"com.ge0rges.Meme_Jump.4000C",@"com.ge0rges.Meme_Jump.9000C", @"com.ge0rges.Meme_Jump.24000C", nil]];

        request.delegate = self;
        [request start];

        [activityindicatorButton24000 startAnimating];
        [activityindicatorButton4000 startAnimating];
        [activityindicatorButton9000 startAnimating];

        activityindicatorButton24000.hidden = NO;
        activityindicatorButton4000.hidden = NO;
        activityindicatorButton9000.hidden = NO;

        CoinsButton4000.hidden = YES;
        CoinsButton9000.hidden = YES;
        CoinsButton24000.hidden = YES;

    } else {

        [CoinsButton4000 setTitle:NSLocalizedString(@"N/A", nil) forState:UIControlStateNormal];
        [CoinsButton9000 setTitle:NSLocalizedString(@"N/A", nil) forState:UIControlStateNormal];
        [CoinsButton24000 setTitle:NSLocalizedString(@"N/A", nil) forState:UIControlStateNormal];

        [CoinsLabel4000 setText:nil];
        [CoinsLabel9000 setText:nil];
        [CoinsLabel24000 setText:nil];

        CoinsButton4000.hidden = NO;
        CoinsButton9000.hidden = NO;
        CoinsButton24000.hidden = NO;

        [activityindicatorButton24000 stopAnimating];
        [activityindicatorButton4000 stopAnimating];
        [activityindicatorButton9000 stopAnimating];

        forButtonsAndLabels = YES;
        forPurchase = NO;
    }
}

#pragma mark - checking internet
- (void)checkNetworkStatus:(NSNotification *)notice
{
    // called after network status changes
    NetworkStatus internetStatus = [internetReachable currentReachabilityStatus];
    switch (internetStatus)
    {
        case NotReachable:
        {
            internetActive = NO;
            forPurchase = NO;
            forButtonsAndLabels = YES;

            [self setButtonsAndLabelsForExtraCoins];

            break;
        }
        case ReachableViaWiFi:
        {
            internetActive = YES;

            [self setButtonsAndLabelsForExtraCoins];

            break;
        }
        case ReachableViaWWAN:
        {
            internetActive = YES;

            [self setButtonsAndLabelsForExtraCoins];

            break;
        }
    }
}

#pragma mark - buying extra coins

- (IBAction)buy4000Coins {

    CoinsButton4000.hidden = YES;

    [activityindicatorButton4000 startAnimating];
    activityindicatorButton4000.hidden = NO;

    if (internetActive == NO) {

        CoinsButton4000.hidden = NO;
        [activityindicatorButton4000 stopAnimating];

        UIAlertView *nointernet = [[UIAlertView alloc]
                                   initWithTitle: NSLocalizedString(@"No internet connection", nil)
                                   message: NSLocalizedString(@"It seems you are not connected to the internet. in-app purchases require a internet connection. Please connect to the internet and try again.", nil)
                         delegate:nil
                         cancelButtonTitle:@"OK"
                         otherButtonTitles:nil, nil];


        [nointernet show];

    } else {

        identifier = @"com.ge0rges.Meme_Jump.4000C";
        [self checkForParentPermission];

    }
}

- (IBAction)buy9000Coins {

    CoinsButton9000.hidden = YES;

    [activityindicatorButton9000 startAnimating];
    activityindicatorButton9000.hidden = NO;

    if (internetActive == NO) {

        CoinsButton9000.hidden = NO;
        [activityindicatorButton9000 stopAnimating];

        UIAlertView *nointernet = [[UIAlertView alloc]
                                   initWithTitle: NSLocalizedString(@"No internet connection", nil)
                                   message: NSLocalizedString(@"It seems you are not connected to the internet. in-app purchases require a internet connection. Please connect to the internet and try again.", nil)
                                   delegate:nil
                                   cancelButtonTitle:@"OK"
                                   otherButtonTitles:nil, nil];


        [nointernet show];

    } else {

        identifier = @"com.ge0rges.Meme_Jump.9000C";
        [self checkForParentPermission];

    }
}

- (IBAction)buy24000Coins {

    CoinsButton24000.hidden = YES;

    [activityindicatorButton24000 startAnimating];
    activityindicatorButton24000.hidden = NO;

    if (internetActive == NO) {

        CoinsButton24000.hidden = NO;
        [activityindicatorButton24000 stopAnimating];

        UIAlertView *nointernet = [[UIAlertView alloc]
                                   initWithTitle: NSLocalizedString(@"No internet connection", nil)
                                   message: NSLocalizedString(@"It seems you are not connected to the internet. in-app purchases require a internet connection. Please connect to the internet and try again.", nil)
                                   delegate:nil
                                   cancelButtonTitle:@"OK"
                                   otherButtonTitles:nil, nil];


        [nointernet show];

    } else {

        identifier = @"com.ge0rges.Meme_Jump.24000C";
        [self checkForParentPermission];

    }
}


#pragma mark - Processing payment

-(void)checkForParentPermission {

    if ([SKPaymentQueue canMakePayments]) {
        if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.4000C"]) {

            SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:@"com.ge0rges.Meme_Jump.4000C"]];

            request.delegate = self;

            [request start];

            [activityindicatorButton4000 startAnimating];
            activityindicatorButton4000.hidden = NO;

        } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.9000C"]) {

            SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:@"com.ge0rges.Meme_Jump.9000C"]];

            request.delegate = self;

            [request start];

            [activityindicatorButton9000 startAnimating];
            activityindicatorButton9000.hidden = NO;

        } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.24000C"]) {

            SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:[NSSet setWithObject:@"com.ge0rges.Meme_Jump.24000C"]];

            request.delegate = self;

            [request start];

            [activityindicatorButton24000 startAnimating];
            activityindicatorButton24000.hidden = NO;
        }

    } else {

        UIAlertView *tmp = [[UIAlertView alloc]
                            initWithTitle:NSLocalizedString(@"Prohibited", nil)
                            message:NSLocalizedString(@"Sorry , Parental Control has prohibited in-app purchases, you cannot make a purchase.", nil)
                            delegate:nil
                            cancelButtonTitle:@"Ok"
                            otherButtonTitles:nil, nil];
        [tmp show];

    }
}

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

{

    if (forButtonsAndLabels == YES && internetActive == YES && forPurchase == NO) {

        [activityindicatorButton4000 stopAnimating];
        [activityindicatorButton9000 stopAnimating];
        [activityindicatorButton24000 stopAnimating];

        product1 = nil;
        product2 = nil;
        product3 = nil;

        int count = (int)[response.products count];

        if (count>0) {
            NSLog(@"%i", count);
            product1 = [response.products objectAtIndex:1];
            product2 = [response.products objectAtIndex:2];
            product3 = [response.products objectAtIndex:0];

            NSNumberFormatter *numberFormatter1 = [[NSNumberFormatter alloc] init];
            [numberFormatter1 setFormatterBehavior:NSNumberFormatterBehavior10_4];
            [numberFormatter1 setNumberStyle:NSNumberFormatterCurrencyStyle];
            [numberFormatter1 setLocale:product1.priceLocale];
            NSString *stringPrice1 = [numberFormatter1 stringFromNumber:product1.price];

            NSNumberFormatter *numberFormatter2 = [[NSNumberFormatter alloc] init];
            [numberFormatter2 setFormatterBehavior:NSNumberFormatterBehavior10_4];
            [numberFormatter2 setNumberStyle:NSNumberFormatterCurrencyStyle];
            [numberFormatter2 setLocale:product2.priceLocale];
            NSString *stringPrice2 = [numberFormatter2 stringFromNumber:product2.price];

            NSNumberFormatter *numberFormatter3 = [[NSNumberFormatter alloc] init];
            [numberFormatter3 setFormatterBehavior:NSNumberFormatterBehavior10_4];
            [numberFormatter3 setNumberStyle:NSNumberFormatterCurrencyStyle];
            [numberFormatter3 setLocale:product3.priceLocale];
            NSString *stringPrice3 = [numberFormatter3 stringFromNumber:product3.price];

            [CoinsButton4000 setTitle:stringPrice1 forState:UIControlStateNormal];
            [CoinsButton9000 setTitle:stringPrice2 forState:UIControlStateNormal];
            [CoinsButton24000 setTitle:stringPrice3 forState:UIControlStateNormal];

            CoinsButton4000.hidden = NO;
            CoinsButton9000.hidden = NO;
            CoinsButton24000.hidden = NO;

            CoinsLabel4000.adjustsFontSizeToFitWidth = NO;
            CoinsLabel9000.adjustsFontSizeToFitWidth = NO;
            CoinsLabel24000.adjustsFontSizeToFitWidth = NO;

            CoinsLabel4000.numberOfLines = 1;
            CoinsLabel9000.numberOfLines = 1;
            CoinsLabel24000.numberOfLines = 1;


            [CoinsLabel4000 setText:product1.localizedTitle];
            [CoinsLabel9000 setText:product2.localizedTitle];
            [CoinsLabel24000 setText:product3.localizedTitle];

            fakePurchase = YES;

        } else {

            [CoinsButton4000 setTitle:NSLocalizedString(@"N/A", nil) forState:UIControlStateNormal];
            [CoinsButton9000 setTitle:NSLocalizedString(@"N/A", nil) forState:UIControlStateNormal];
            [CoinsButton24000 setTitle:NSLocalizedString(@"N/A", nil) forState:UIControlStateNormal];

            [CoinsLabel4000 setText:nil];
            [CoinsLabel9000 setText:nil];
            [CoinsLabel24000 setText:nil];

            CoinsButton4000.hidden = NO;
            CoinsButton9000.hidden = NO;
            CoinsButton24000.hidden = NO;

            [activityindicatorButton24000 stopAnimating];
            [activityindicatorButton4000 stopAnimating];
            [activityindicatorButton9000 stopAnimating];

            forButtonsAndLabels = YES;
            forPurchase = NO;
            fakePurchase = YES;

        }

    } else if (forPurchase == YES && internetActive == YES && fakePurchase == NO) {

        validProduct = nil;

        int count = (int)[response.products count];

        if (count>0) {

            validProduct = [response.products objectAtIndex:0];

            SKPayment *payment = [SKPayment paymentWithProduct:validProduct];

            [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

            [[SKPaymentQueue defaultQueue] addPayment:payment]; // <-- KA CHING!


        } else {

            UIAlertView *notAvail = [[UIAlertView alloc]
                                     initWithTitle:NSLocalizedString(@"Failed", nil)
                                     message:NSLocalizedString(@"Sorry there seems to be a problem. Please try again later.", nil)
                                     delegate:nil
                                     cancelButtonTitle:@"Ok"
                                     otherButtonTitles:nil, nil];

            [notAvail show];

        }

    } else {

        [CoinsButton4000 setTitle:NSLocalizedString(@"N/A", nil) forState:UIControlStateNormal];
        [CoinsButton9000 setTitle:NSLocalizedString(@"N/A", nil) forState:UIControlStateNormal];
        [CoinsButton24000 setTitle:NSLocalizedString(@"N/A", nil) forState:UIControlStateNormal];

        [CoinsLabel4000 setText:nil];
        [CoinsLabel9000 setText:nil];
        [CoinsLabel24000 setText:nil];

        CoinsButton4000.hidden = NO;
        CoinsButton9000.hidden = NO;
        CoinsButton24000.hidden = NO;

        [activityindicatorButton24000 stopAnimating];
        [activityindicatorButton4000 stopAnimating];
        [activityindicatorButton9000 stopAnimating];

        forButtonsAndLabels = YES;
        forPurchase = NO;
        fakePurchase = YES;
    }
}

-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
    for (SKPaymentTransaction *transaction in transactions) {
        switch (transaction.transactionState) {
            case SKPaymentTransactionStatePurchasing:
            {
                if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.4000C"]) {

                    [activityindicatorButton4000 startAnimating];
                    activityindicatorButton4000.hidden = NO;

                } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.9000C"]) {

                    [activityindicatorButton9000 startAnimating];
                    activityindicatorButton9000.hidden = NO;

                } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.24000C"]) {

                    [activityindicatorButton24000 startAnimating];
                    activityindicatorButton24000.hidden = NO;

                }

                break;
            }

            case SKPaymentTransactionStatePurchased:
            {
                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

                int receiptValue = (int)[self verifyReceipt:transaction];

                if (receiptValue == 0) {

                    if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.4000C"]) {

                        CoinsButton4000.hidden = NO;
                        [activityindicatorButton4000 stopAnimating];

                        UIAlertView *complete = [[UIAlertView alloc]
                                                 initWithTitle:NSLocalizedString(@"Complete", nil)
                                                 message:NSLocalizedString(@"You have received 4000 Coins.", nil)
                                                 delegate:nil
                                                 cancelButtonTitle:NSLocalizedString(@"Awesome!", nil)
                                                 otherButtonTitles:nil, nil];
                        [complete show];

                        allCoins += 4000;

                        [self setItUp];

                    } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.9000C"]) {

                        CoinsButton9000.hidden = NO;
                        [activityindicatorButton9000 stopAnimating];

                        UIAlertView *complete = [[UIAlertView alloc]
                                                 initWithTitle:NSLocalizedString(@"Complete", nil)
                                                 message:NSLocalizedString(@"You have received 9000 Coins.", nil)
                                                 delegate:nil
                                                 cancelButtonTitle:NSLocalizedString(@"Awesome!", nil)
                                                 otherButtonTitles:nil, nil];
                        [complete show];

                        allCoins += 9000;

                        [self setItUp];

                    } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.24000C"]) {

                        CoinsButton24000.hidden = NO;
                        [activityindicatorButton24000 stopAnimating];

                        UIAlertView *complete = [[UIAlertView alloc]
                                                 initWithTitle:NSLocalizedString(@"Complete", nil)
                                                 message:NSLocalizedString(@"You have received 24000 Coins.", nil)
                                                 delegate:nil
                                                 cancelButtonTitle:NSLocalizedString(@"Awesome!", nil)
                                                 otherButtonTitles:nil, nil];
                        [complete show];

                        allCoins += 24000;

                        [self setItUp];

                    }

                } else {


                    UIAlertView *failed = [[UIAlertView alloc]
                                           initWithTitle:NSLocalizedString(@"Receipt Invalid", nil)
                                           message:NSLocalizedString(@"The receipt could not be verified. If you are jailbroken please check for tweaks that may interfere with connection to iTunes or provide free in-app purchases 'like IAP-Cracker', otherwise check your internet connection. And don't worry you have not been charged", nil)
                                           delegate:nil
                                           cancelButtonTitle:@"Ok"
                                           otherButtonTitles:nil, nil];
                    [failed show];


                    if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.4000C"]) {

                        CoinsButton4000.hidden = NO;
                        [activityindicatorButton4000 stopAnimating];

                    } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.9000C"]) {

                        CoinsButton9000.hidden = NO;
                        [activityindicatorButton9000 stopAnimating];

                    } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.24000C"]) {

                        CoinsButton24000.hidden = NO;
                        [activityindicatorButton24000 stopAnimating];

                    }

                }

                break;
            }

            case SKPaymentTransactionStateRestored:
            {

                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

                if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.4000C"]) {

                    CoinsButton4000.hidden = NO;
                    [activityindicatorButton4000 stopAnimating];

                } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.9000C"]) {

                    CoinsButton9000.hidden = NO;
                    [activityindicatorButton9000 stopAnimating];

                } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.24000C"]) {

                    CoinsButton24000.hidden = NO;
                    [activityindicatorButton24000 stopAnimating];

                }

                break;
            }

            case SKPaymentTransactionStateFailed:
            {
                if (transaction.error.code != SKErrorPaymentCancelled && forPurchase == YES && fakePurchase == NO) {

                    UIAlertView *failed = [[UIAlertView alloc]
                                           initWithTitle:NSLocalizedString(@"Failed", nil)
                                           message:transaction.error.localizedDescription
                                           delegate:nil
                                           cancelButtonTitle:@"Ok"
                                           otherButtonTitles:nil, nil];
                    [failed show];


                } 

                [[SKPaymentQueue defaultQueue] finishTransaction:transaction];

                if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.4000C"]) {

                    CoinsButton4000.hidden = NO;
                    [activityindicatorButton4000 stopAnimating];

                } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.9000C"]) {

                    CoinsButton9000.hidden = NO;
                    [activityindicatorButton9000 stopAnimating];

                } else if ([identifier isEqualToString:@"com.ge0rges.Meme_Jump.24000C"]) {

                    CoinsButton24000.hidden = NO;
                    [activityindicatorButton24000 stopAnimating];

                }

                fakePurchase = NO;

                break;
            }
        }
    }
}

#pragma mark - verifying purchases

- (NSInteger)verifyReceipt:(SKPaymentTransaction *)transaction {

    NSString *jsonObjectString = [self encode:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];
    NSString *completeString = [NSString stringWithFormat:@"http://ge0rges.com/verifyiap/verifyiap.php?receipt=%@", jsonObjectString];

    NSURL *urlForValidation = [NSURL URLWithString:completeString];

    NSMutableURLRequest *validationRequest = [[NSMutableURLRequest alloc] initWithURL:urlForValidation];
    [validationRequest setHTTPMethod:@"GET"];

    NSData *responseData = [NSURLConnection sendSynchronousRequest:validationRequest returningResponse:nil error:nil];

    NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];

    NSInteger response = [responseString integerValue];

    return response;
}

- (NSString *)encode:(const uint8_t *)input length:(NSInteger)length {

    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    NSMutableData *data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t *output = (uint8_t *)data.mutableBytes;

    for (NSInteger i = 0; i < length; i += 3) {
        NSInteger value = 0;
        for (NSInteger j = i; j < (i + 3); j++) {
            value <<= 8;

            if (j < length) {
                value |= (0xFF & input[j]);
            }
        }

        NSInteger index = (i / 3) * 4;
        output[index + 0] =                    table[(value >> 18) & 0x3F];
        output[index + 1] =                    table[(value >> 12) & 0x3F];
        output[index + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';
        output[index + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';
    }

    return [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)viewDidUnload {
    [super viewDidUnload];

    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end
4

1 回答 1

0

根据您的崩溃,您的 SKProductsRequest 返回的项目似乎比您预期的要少,并且您正在访问返回数组的末尾。您应该在访问其中的内容之前确认该数组的大小。

至于该数组可能小于预期的原因,您应该在 iTunes 连接中查找这些 IAP 的任何问题,或者在 Google 中查找 IAP 调试提示。

于 2013-10-20T00:26:04.203 回答