我在移动应用中实施应用内购买时遇到问题。
基本上,有时用户会收取两次费用。 并且当用户在应用程序中被打断时 - 比如他们被重定向回iTunes以完成付款然后回到应用程序,他们会看到错误“发生了错误......”
我是否正确实施了应用内购买?
这是我的代码:
我做错了什么?
- (void) myLeftAction {
[self performSegueWithIdentifier: @"login" sender: self];
}
- (void)viewDidLoad {
[super viewDidLoad];
UISwipeGestureRecognizer * recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(myLeftAction)];
[recognizer setDirection:(UISwipeGestureRecognizerDirectionRight)];
[self.view addGestureRecognizer:recognizer];
done = NO;
paymentProcessing = NO;
shownProducts = [NSArray arrayWithObjects: @"com.example.a", @"com.example.b", @"com.example.c", @"com.example.d", nil];
hud = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
hud.labelText = @"Loading";
[self fetchAvailableProducts];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(void)fetchAvailableProducts {
if ([SKPaymentQueue canMakePayments])
{
NSSet *productIdentifiers = [NSSet setWithObjects: @"com.example.a", @"com.example.b", @"com.example.c", @"com.example.d",nil];
productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
productsRequest.delegate = self;
[productsRequest start];
}
else {
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:
@"Purchases are disabled in your device. Please enable in-app purchases before continuing." message:nil delegate:
self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alertView show];
}
}
- (BOOL)canMakePurchases {
return [SKPaymentQueue canMakePayments];
}
- (void)purchaseMyProduct:(SKProduct*)product {
if ([self canMakePurchases]) {
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addTransactionObserver: self];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
else{
paymentProcessing = NO;
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle: @"Purchases are disabled on your device. Please enable in-app purchases before continuing." message:nil delegate: self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alertView show];
}
}
-(IBAction)purchase:(id)sender
{
if(done && !paymentProcessing) {
paymentProcessing = YES;
chosenProduct = [validProducts objectAtIndex: [sender tag]];
[self purchaseMyProduct: chosenProduct];
}
}
#pragma mark StoreKit Delegate
-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
[self occuringTransaction: transaction];
break;
case SKPaymentTransactionStatePurchased:
[self completeTransaction: transaction];
break;
case SKPaymentTransactionStateRestored:
[self restoreTransaction: transaction];
break;
case SKPaymentTransactionStateFailed:
[self failedTransaction: transaction];
break;
default:
break;
}
}
}
- (void) occuringTransaction:(SKPaymentTransaction *)transaction
{
[hud show: YES];
NSLog(@"Purchasing");
}
- (void) processPurchase: (SKPaymentTransaction *)transaction
{
id<FBGraphUser> fb = [[Auth sharedInstance] user];
NSString * firstName = fb.first_name;
NSString * lastName = fb.last_name;
NSString * email = [fb objectForKey: @"email"];
NSString * facebook_id = fb.id;
PFObject * result = [PFObject objectWithClassName:@"payments"];
result[@"firstName"] = firstName;
result[@"lastName"] = lastName;
result[@"email"] = email;
result[@"facebookId"] = facebook_id;
result[@"package"] = transaction.payment.productIdentifier;
result[@"transactionId"] = transaction.transactionIdentifier;
result[@"transactionError"] = transaction.error.localizedDescription;
NSString *dateString = [NSDateFormatter localizedStringFromDate: transaction.transactionDate
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterFullStyle];
result[@"transactionDate"] = dateString;
result[@"transactionState"] = [NSString stringWithFormat: @"%ld", transaction.transactionState];
[result saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error)
{
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:
@"Purchase is completed successfully. You can now choose the hashtags you want shown in your review on lulu." message:nil delegate:
self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alertView show];
NSString * category = @"";
if(
[transaction.payment.productIdentifier isEqualToString: @"com.fakemylulu.player_1"] ||
[transaction.payment.productIdentifier isEqualToString: @"com.fakemylulu.player_3"]
) {
category = @"a";
}
else {
category = @"b";
}
paymentProcessing = NO;
[hud hide:YES];
//push view manually
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
fmHashtagsViewController *ivc = [storyboard instantiateViewControllerWithIdentifier:@"hashtags"];
ivc.category = transaction.payment.productIdentifier;
[self.navigationController pushViewController:ivc animated:NO];
}];
}
-(void)completeTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"Completed transaction");
if([transaction.payment.productIdentifier isEqualToString: chosenProduct.productIdentifier]) {
[self processPurchase: transaction];
}
}
-(void)restoreTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"Restored transaction");
[self processPurchase: transaction];
}
-(void)failedTransaction:(SKPaymentTransaction *)transaction
{
[hud hide: YES];
paymentProcessing = NO;
if(transaction.error.code != SKErrorPaymentCancelled)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"An error occured! We could not process your payment. Please try again."
message:[transaction.error localizedDescription]
delegate:nil
cancelButtonTitle:nil
otherButtonTitles:@"OK", nil];
[alert show];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}
-(void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSInteger count = [response.products count];
if (count>0)
{
validProducts = response.products;
NSUInteger index = 0;
for (SKProduct * x in validProducts)
{
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehavior10_4];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale: x.priceLocale];
NSString *formattedPrice = [numberFormatter stringFromNumber: x.price];
if([x.productIdentifier isEqualToString: @"com.fakemylulu.romantic_1"]) {
[self.a setTitle: [NSString stringWithFormat: @"%@", formattedPrice] forState:UIControlStateNormal];
self.a.tag = index;
}
else if([x.productIdentifier isEqualToString: @"com.fakemylulu.romantic_3"])
{
[self.b setTitle: [NSString stringWithFormat: @"%@", formattedPrice] forState:UIControlStateNormal];
self.b.tag = index;
}
else if([x.productIdentifier isEqualToString: @"com.fakemylulu.player_1"])
{
[self.c setTitle: [NSString stringWithFormat: @"%@", formattedPrice] forState:UIControlStateNormal];
self.c.tag = index;
}
else if([x.productIdentifier isEqualToString: @"com.fakemylulu.player_3"])
{
[self.d setTitle: [NSString stringWithFormat: @"%@", formattedPrice] forState:UIControlStateNormal];
self.d.tag = index;
}
index += 1;
}
done = YES;
} else {
UIAlertView *tmp = [[UIAlertView alloc]
initWithTitle:@"Not Available"
message:@"No products available for purchase"
delegate:self
cancelButtonTitle:nil
otherButtonTitles:@"Ok", nil];
[tmp show];
}
[hud hide:YES];
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
NSLog(@"Failed to load list of products. %@", error);
UIAlertView *tmp = [[UIAlertView alloc]
initWithTitle:@"Oops"
message:@"There was an error retrieving the list of products. Please try this app again later."
delegate:self
cancelButtonTitle:nil
otherButtonTitles:@"Ok", nil];
[tmp show];
}
- (void)dealloc {
if ([SKPaymentQueue canMakePayments]) {
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
}
答案 0 :(得分:0)
首先您必须说明什么类型的订阅。 iOS中有三种主要的应用内购买类型: 1)非消耗品。 2)消耗品。 3)订阅。 在自动续订订阅中,它将每5分钟自动续订一次。 因为在sanbox帐户中使用1个月,需要5分钟。
如果是耗材:这些是用户可以多次购买的东西。通常它们会“用完”,因此用户可以再次购买
非消耗品:这些是用户购买的东西(只有一次),然后可以永久访问。