首先让我说,我的应用内购买有效。
我已经在活动指示器/线程上苦苦挣扎了一个多星期了。我在让我的微调器(UIActivityIndicatorView)在我的 InAppPurchase.m 中发挥出色时遇到了真正的问题
我在许多其他地方使用相同的线程代码,它工作正常。
IAP 进程的工作方式是否会导致基本线程出现问题?
现在,微调器在您点击购买按钮和出现第一个警报(“您要购买吗?...”)之间旋转,但之后没有微调器。
这是 .m 文件:
// InAppPurchaseManager.m
#import "InAppPurchaseManager.h"
#import "GANTracker.h"
@implementation InAppPurchaseManager
@synthesize productID;
@synthesize productsRequest;
@synthesize closeButton;
@synthesize buyButton;
@synthesize testLabel;
@synthesize pView;
@synthesize spinner;
@synthesize spinnerLabel;
- (void)dealloc {
[productID release];
//[productsRequest release];
[closeButton release];
[buyButton release];
[testLabel release];
[pView release];
[spinner release];
[spinnerLabel release];
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
[super dealloc];
}
- (void)viewDidLoad {
[super viewDidLoad];
NSError *error;
if (![[GANTracker sharedTracker] trackPageview:@"/in_app_purchase" withError:&error]) {
//NSLog(@"No GAN Tracking");
}
UIColor *backgroundColor = [UIColor colorWithRed:.6745 green:.1333 blue:.1333 alpha:1];
pView.backgroundColor = backgroundColor;
[closeButton release];
closeButton = [[UIBarButtonItem alloc] initWithTitle:@"Close" style:UIBarButtonItemStyleBordered target:self action:@selector(closeButtonAction:)];
self.navigationItem.leftBarButtonItem = closeButton;
// create the "Loading..." label
[spinnerLabel release];
//CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
spinnerLabel = [[UILabel alloc] initWithFrame:CGRectMake(35, 145, 250, 35)];
[spinnerLabel setText:@"Connecting to App Store... "];
[spinnerLabel setTextColor:[UIColor whiteColor]];
[spinnerLabel setBackgroundColor:[UIColor blackColor]];
[spinnerLabel setTextAlignment:UITextAlignmentRight];
[self.view addSubview:spinnerLabel];
spinnerLabel.hidden = YES;
// create the spinner
[spinner release];
spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[spinner setCenter:CGPointMake(55,162)];
[self.view addSubview:spinner];
spinner.backgroundColor = [UIColor blackColor];
spinner.hidesWhenStopped = YES;
[spinner stopAnimating];
self.navigationItem.title = @"Credits";
//[self spinTheSpinner];
//[self loadStore];
[NSThread detachNewThreadSelector:@selector(loadStore) toTarget:self withObject:nil];
}
-(void)viewDidAppear:(BOOL)animated {
[self doneSpinning];
[self updateButtonStatus:@"ON"];
}
-(void)spinTheSpinner {
NSLog(@"In App Purchase.m == SpinTheSpiner");
//NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[spinner startAnimating];
spinnerLabel.hidden=NO;
//[self performSelectorOnMainThread:@selector(doneSpinning) withObject:nil waitUntilDone:NO];
//[pool release];
}
-(void)doneSpinning {
NSLog(@"In App Purchase.m == DoneSpinning");
spinnerLabel.hidden = YES;
[spinner stopAnimating];
}
-(void)closeButtonAction:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
-(void)buyButtonAction:(id)sender {
if([self canMakePurchases]) {
[self updateButtonStatus:@"OFF"];
[self spinTheSpinner];
//[self performSelectorOnMainThread:@selector(requestInAppPurchaseData) withObject:nil waitUntilDone:NO];
[NSThread detachNewThreadSelector:@selector(requestInAppPurchaseData) toTarget:self withObject:nil];
} else {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:[NSString stringWithString:@"Your account settings do not allow for In App Purchases."] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alertView show];
[alertView release];
}
}
-(void)updateButtonStatus:(NSString *)status {
if ([status isEqual:@"OFF"]) {
closeButton.enabled = NO;
buyButton.enabled = NO;
buyButton.titleLabel.textColor = [UIColor grayColor];
} else {
closeButton.enabled = YES;
buyButton.enabled = YES;
buyButton.titleLabel.textColor = [UIColor blueColor];
}
}
#pragma mark -
#pragma mark SKProductsRequestDelegate methods
//
// call this method once on startup
//
- (void)loadStore
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Load Store");
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
// restarts any purchases if they were interrupted last time the app was open
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[self doneSpinning];
[pool release];
}
- (void)requestInAppPurchaseData
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog(@"Request In App Purchase Data");
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
NSSet *productIdentifiers = [NSSet setWithObject:kInAppPurchaseCreditProductId];
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
//[self doneSpinning];
[pool release];
// we will release the request object in the delegate callback
}
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSLog(@"did Receive Response");
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
NSArray *products = response.products;
productID = [products count] == 1 ? [[products objectAtIndex:0] retain] : nil;
if (productID)
{
/*
NSLog(@"Product title: %@" , productID.localizedTitle);
NSLog(@"Product description: %@" , productID.localizedDescription);
NSLog(@"Product price: %@" , productID.price);
NSLog(@"Product id: %@" , productID.productIdentifier);
*/
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *currentCredits = ([standardUserDefaults objectForKey:@"currentCredits"]) ? [standardUserDefaults objectForKey:@"currentCredits"] : @"0";
testLabel.text = [NSString stringWithFormat:@"%@", currentCredits];
}
for (NSString *invalidProductId in response.invalidProductIdentifiers)
{
//NSLog(@"Invalid product id: %@" , invalidProductId);
testLabel.text = @"Try Again Later.";
}
// finally release the reqest we alloc/init’ed in requestProUpgradeProductData
[productsRequest release];
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerProductsFetchedNotification object:self userInfo:nil];
//[self performSelectorOnMainThread:@selector(purchaseCredit) withObject:nil waitUntilDone:NO];
[self purchaseCredit];
}
//
// call this before making a purchase
//
- (BOOL)canMakePurchases
{
NSLog(@"Can Make Payments");
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
return [SKPaymentQueue canMakePayments];
}
//
// kick off the upgrade transaction
//
- (void)purchaseCredit
{
// REMOVED FOR PRIVACY
}
#pragma -
#pragma Purchase helpers
//
// saves a record of the transaction by storing the receipt to disk
//
- (void)recordTransaction:(SKPaymentTransaction *)transaction
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
if ([transaction.payment.productIdentifier isEqualToString:kInAppPurchaseCreditProductId])
{
// save the transaction receipt to disk
[[NSUserDefaults standardUserDefaults] setValue:transaction.transactionReceipt forKey:@"InAppPurchaseTransactionReceipt" ];
[[NSUserDefaults standardUserDefaults] synchronize];
}
[pool release];
}
//
// enable pro features
//
- (void)provideContent:(NSString *)productId
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
if ([productId isEqualToString:kInAppPurchaseCreditProductId])
{
// Increment currentCredits
NSUserDefaults *standardUserDefaults = [NSUserDefaults standardUserDefaults];
NSString *currentCredits = [standardUserDefaults objectForKey:@"currentCredits"];
int newCreditCount = [currentCredits intValue] + 1;
[standardUserDefaults setObject:[NSString stringWithFormat:@"%d", newCreditCount] forKey:@"currentCredits"];
testLabel.text = [NSString stringWithFormat:@"%d", newCreditCount];
}
[pool release];
}
//
// removes the transaction from the queue and posts a notification with the transaction result
//
- (void)finishTransaction:(SKPaymentTransaction *)transaction wasSuccessful:(BOOL)wasSuccessful
{
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
// remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:transaction, @"transaction" , nil];
if (wasSuccessful)
{
// send out a notification that we’ve finished the transaction
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionSucceededNotification object:self userInfo:userInfo];
}
else
{
// send out a notification for the failed transaction
[[NSNotificationCenter defaultCenter] postNotificationName:kInAppPurchaseManagerTransactionFailedNotification object:self userInfo:userInfo];
}
[self updateButtonStatus:@"ON"];
}
//
// called when the transaction was successful
//
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
[self updateButtonStatus:@"OFF"];
[self spinTheSpinner];
[NSThread detachNewThreadSelector:@selector(recordTransaction:) toTarget:self withObject:transaction];
[NSThread detachNewThreadSelector:@selector(provideContent:) toTarget:self withObject:transaction.payment.productIdentifier];
//[self recordTransaction:transaction];
//[self provideContent:transaction.payment.productIdentifier];
[NSThread detachNewThreadSelector:@selector(threadFinishTransaction:) toTarget:self withObject:transaction];
//[self finishTransaction:transaction wasSuccessful:YES];
NSError *error;
if (![[GANTracker sharedTracker] trackPageview:@"/in_app_purchase_done" withError:&error]) {
//NSLog(@"No GAN Tracking");
}
[self doneSpinning];
}
-(void)threadFinishTransaction:(SKPaymentTransaction *)transaction {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[self finishTransaction:transaction wasSuccessful:YES];
[pool release];
}
//
// called when a transaction has been restored and and successfully completed
//
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
[self recordTransaction:transaction.originalTransaction];
[self provideContent:transaction.originalTransaction.payment.productIdentifier];
[self finishTransaction:transaction wasSuccessful:YES];
}
//
// called when a transaction has failed
//
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
if (transaction.error.code != SKErrorPaymentCancelled)
{
// error!
NSError *error;
if (![[GANTracker sharedTracker] trackPageview:@"/in_app_purchase_error" withError:&error]) {
//NSLog(@"No GAN Tracking");
}
[self finishTransaction:transaction wasSuccessful:NO];
}
else
{
// this is fine, the user just cancelled, so don’t notify
NSError *error;
if (![[GANTracker sharedTracker] trackPageview:@"/in_app_purchase_cancel" withError:&error]) {
//NSLog(@"No GAN Tracking");
}
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
[self updateButtonStatus:@"ON"];
}
#pragma mark -
#pragma mark SKPaymentTransactionObserver methods
//
// called when the transaction status is updated
//
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
//[NSThread detachNewThreadSelector:@selector(spinTheSpinner) toTarget:self withObject:nil];
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;
}
}
}
@end