iOS In app purchase不会在已购买的商品上调用restoreTransaction

时间:2013-08-09 12:04:07

标签: iphone ios ipad in-app-purchase

我正在使用ios进行应用程序购买并且我有一些疑问,这些疑问将有助于像我这样的新人在应用程序购买中理解。

1)我的应用程序出现问题,如果用户“将我的应用程序安装到新设备或同一设备中,如果他之前删除了我的应用程序”,那时用户尝试购买已经购买的商品我的代码不会调用{{1}在restoreTransaction

的切换案例中

我收到updatedTransactions的消息,它调用you ve already purchased this tap okay to downlaod it FREE Enviornment sandbox案例,但它没有调用SKPaymentTransactionStatePurchased我的情况会出现什么问题..

所以我已经实现了单独的恢复按钮来恢复用户已经提供的所有视频项目,所以只需要知道它会拒绝我在苹果商店的应用程序吗?

2)购买商品只需要一次密码,之后就不会要求我输入密码。它直接显示带有确认按钮的对话框,但我的项目经理表示应该为每件商品购买密码。

每当我尝试恢复Purchase..strange时都要求输入密码。

3)目前我在沙盒中进行测试时,我尝试使用真正的苹果ID购买显示购买失败(我必须使用测试帐户来测试购买,因为苹果文档说)但我的项目经理说它应该要求新的如果你在沙箱中测试,请测试用户名(因为文档说你必须手动设置注销,但我的项目经理想要自动执行),

所以只需要问一下,是否有可能通过编码登出并显示标志牌(我知道这不可能,但我要求的信息)

4)目前我的应用程序正在沙箱环境中工作,但我是否需要为我的应用程序更改实际购买的内容?或者当苹果验证我的应用程序并在应用程序上签名时,苹果会自动将沙箱更改为实际购买店?

5)我在我自己的服务器上验证交易,所以我发送沙箱1,如果我在沙箱环境,否则我必须发送0(目前我硬编码沙箱值为1)所以是否有任何方法来检测环境是沙箱还是真的?

这是我的购买代码和恢复按钮代码 任何帮助表示赞赏

购买代码

SKPaymentTransactionStateRestored

恢复简单

- (IBAction)PaymentButton:(id)sender {

loadingHUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
loadingHUD.labelText = NSLocalizedString(@"Loading", nil);
[loadingHUD show:YES];
[self startPurchase];// call the restore Purchase method

  //[loadingHUD showWhileExecuting:@selector(startPurchase) onTarget:self withObject:nil animated:YES];// call the restore Purchase method
  }

- (void)startPurchase {
if([SKPaymentQueue canMakePayments]) {
    NSLog(@"IN-APP:can make payments");
    [self requestProductData];
}
else {
    NSLog(@"IN-APP:can't make payments");
    loadingHUD.hidden=YES;
 }
}

 - (void)requestProductData {
NSLog(@"IN-APP:requestProductData");
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject:myIdentifier]];
request.delegate = self;
[request start];
NSLog(@"IN-APP:requestProductData END");
NSLog(@"Productdata is %@",myIdentifier);

   }

 - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
  [[SKPaymentQueue defaultQueue] addTransactionObserver:self];  
   @try {
    SKProduct *product = [response.products objectAtIndex:0];
    SKPayment *newPayment = [SKPayment paymentWithProduct:product];
    [[SKPaymentQueue defaultQueue] addPayment:newPayment];
    NSLog(@"IN-APP:productsRequest END");

  }
 @catch (NSException *exception) {

     // Failed to purchase Hide the progress bar and Display Error Dialog
     loadingHUD.hidden=YES;
     UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Error in Product id can not purchase" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
     [alertView show];

   }

   }


    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
  {
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];
        default:
            break;
    }
    }
   }


    - (void) completeTransaction: (SKPaymentTransaction *)transaction
    {
NSLog(@"Transaction Completed");
// Finally, remove the transaction from the payment queue.
[self verifyReceipt:transaction]; // Call the verifyReceipt method to send transaction.bytes

 NSLog(@"Purchase Transaction finish");
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
     }

  - (void) restoreTransaction: (SKPaymentTransaction *)transaction

  NSLog(@"Transaction Restored %@",transaction.originalTransaction.payment.productIdentifier);
// You can create a method to record the transaction.
// [self recordTransaction: transaction];
loadingHUD.hidden=YES;

// You should make the update to your app based on what was purchased and inform user.
// [self provideContent: transaction.payment.productIdentifier];
// Finally, remove the transaction from the payment queue.
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
  }

   - (void) failedTransaction: (SKPaymentTransaction *)transaction
   {
loadingHUD.hidden=YES;// hide loadingHUD

  if (transaction.error.code != SKErrorPaymentCancelled)
  {
    // Display an error here.
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Purchase Unsuccessful"
                                                    message:@"Your purchase failed. Please try again."
                                                   delegate:self
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];
}
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
  }

2 个答案:

答案 0 :(得分:2)

恕我直言,如果有不同的问题,你最好在一定数量上回答这个问题。

无论如何,我会尽力回答:

1)这就是它的意思。 如果您手动调用SKPaymentTransactionStateRestored,则只能使用restoreCompletedTransactions 进行交易。 AFAIK,这是为此创建一个按钮(例如,“恢复购买”)的常规做法。

2)不能说什么。通常情况下,每次,当您的应用程序要进行购买(并收取一些用户的钱)时,它应该询问用户密码。

3)AFAIK,没有。您通过iTunes / AppStore应用程序使用Apple服务器。记住用户的iTunes帐户是他们的事。而且我认为他们没有给你任何方法让当前用户退出。您的项目经理应该理解: - )

4),5)在您尝试验证收据之前,生产/沙箱环境没有区别。如果您谈论使用服务器,我希望您使用服务器来验证收据。

在设备方面,您所做的就是使用StoreKit框架。您没有定义Apple服务器的任何URL,您只需使用框架的类并调用它的方法。 AFAIK,您无需同时对沙箱和生产支持的代码进行任何更改。

但是在您的服务器端,存在差异:当您的应用已经投入生产时,您应该向https://buy.itunes.apple.com/verifyReceipt发送HTTP POST请求。另一方面,当您的应用仍在沙盒中时,请使用https://sandbox.itunes.apple.com/verifyReceipt

如何处理?观看有关自动续订订阅的WWDC 2012视频308。他们建议两种方式:

1)智能服务器。当您的应用程序将收据发送到您的服务器时,它还会传递一些参数,让服务器知道哪个Apple的服务器要使用。我看,你已经使用过这种方法了。

2)反应性服务器。您的服务器始终将收据发送到Apple的生产服务器。您检查响应,如果状态为21007(在文档后面,“此收据是沙箱收据,但它已发送到生产服务部门进行验证。”),您将相同的请求发送到Apple的沙箱服务器

答案 1 :(得分:0)

使用此代码,它可能对您有帮助....

    //To Show Alert of InAppPurchase
    - (void)showAlert
    {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" message:@"Click buy to 
    purchase full tracks and other functionalities of the application." delegate:self
                                      cancelButtonTitle:nil otherButtonTitles:nil, nil];

    [alert addButtonWithTitle:@"Buy"];
    [alert addButtonWithTitle:@"Restore Transaction"];
    [alert addButtonWithTitle:@"Cancel"];
    [alert show];
    }


    -(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:
    (NSInteger)buttonIndex{

    if(buttonIndex==0)
    {
    // For buy an item
    [self Declarations];
    }

    else if(buttonIndex == 1)
    {
    //For Restore Previous Transaction
    [self restorePreviousTransaction:nil];
    }

    else
    {
       //Do something here..
    }
 }

   #pragma mark In App Purchase

   -(void)Declarations
   {
     if ([SKPaymentQueue canMakePayments]) {

     NSLog(@"parental functions are disabled");

     SKProductsRequest *productRequest = [[SKProductsRequest 
     alloc]initWithProductIdentifiers:[NSSet 
     setWithObjects:@"com.tapmobi.careerandsuccess.inapp",nil]];

     productRequest.delegate=self;

     [productRequest start];

     [MBProgressHUD showHUDAddedTo:self.view animated:YES];

     }

     else 
     {
    NSLog(@"parental functions are enabled");
     }
  }

  - (IBAction)restorePreviousTransaction:(id)sender {

    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];

    [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
  }

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

  SKProduct *validProduct=nil;

  int count = [response.products count];

  NSLog(@"number of prouducts present:%d",count);

  if(count==0){

    [MBProgressHUD hideAllHUDsForView:self.view animated:YES];
    return;

  }

  validProduct = [response.products objectAtIndex:0];

  NSLog(@"the product is :%@",validProduct.localizedTitle);

  SKPayment *skpayment = [SKPayment paymentWithProduct:validProduct];

  [[SKPaymentQueue defaultQueue] addPayment:skpayment];

  [[SKPaymentQueue defaultQueue]addTransactionObserver:self];

 }


 -(void)requestDidFinish:(SKRequest *)request
 {
     [MBProgressHUD hideAllHUDsForView:self.view animated:YES];
 }

 -(void)request:(SKRequest *)request didFailWithError:(NSError *)error
 {
     [MBProgressHUD hideAllHUDsForView:self.view animated:YES];

      NSLog(@"Failed to connect with error: %@", [error localizedDescription]);
 }

 -(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
 {
     [MBProgressHUD hideAllHUDsForView:self.view animated:YES];

     NSString *message = [[NSString alloc]init];

     BOOL bSuccess = NO;

     for (SKPaymentTransaction *transaction in transactions) {

     switch (transaction.transactionState) 
     {
        case SKPaymentTransactionStatePurchasing:

            NSLog(@"stuff is getting purchased");
            break;

        case SKPaymentTransactionStatePurchased:

            NSLog(@"purchased properly");
            message = @"Thank you.";

            [[NSUserDefaults standardUserDefaults] setValue:@"Full Version"        
            forKey:PURCHASED_KEY];

            [[SKPaymentQueue defaultQueue]finishTransaction:transaction];
            bSuccess = YES;

            break;

        case SKPaymentTransactionStateRestored:

            [[SKPaymentQueue defaultQueue]finishTransaction:transaction];
            break;

        case SKPaymentTransactionStateFailed:

            if (transaction.error.code != SKErrorPaymentCancelled) {
                NSLog(@"error happened");

                message = @"Purchase is not successfull. Try again later";
            }

            [[SKPaymentQueue defaultQueue]finishTransaction:transaction];
            break;

        default:
            break;
      }     
   }

    if (bSuccess){

        UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"" message:message   
        delegate:nil cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];

        [alert show];
        }
   }

快乐编码..