我最近向 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