iphone – iOS在应用内购买时,不会在已购买的商品上调用restoreTransaction

我正在使用ios进行应用程序购买,我有一些疑问,这些疑问将有助于像我这样的新鲜事,因此了解在应用程序购买.

1)我的应用程序中出现问题,如果用户“将我的应用程序安装到新设备或同一设备中,如果他之前删除我的应用程序”,那时用户尝试购买已购买的项目我的代码不会在切换案例中更新事务中的callrestoreTransaction

我收到消息说你已经购买了这个点击好了下载它免费Enviornment沙箱并且它调用SKPaymentTransactionStatePurchased案例但它没有调用SKPaymentTransactionStateRestored我的情况下会出现什么问题..

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

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

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

3)目前我正在测试沙箱,当我尝试用真正的苹果ID购买它显示购买失败(我必须使用测试帐户测试购买苹果文件说)但我的项目经理说它应该要求新的测试用户名如果你正在沙盒中测试(因为文件说你必须手动设置退出,但我的项目经理想要它自动完成),

所以只需要问一下,是否有可能通过编码注销和显示标志盒(我知道它不可能,但我要问的信息)

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

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

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

购买代码

- (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];
  }

恢复简单

-(void)startRestore 
  {
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; 
}
- (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
 {
if ([queue.transactions count] == 0)
{
    HUD.hidden=YES;
    UIAlertView *restorealert = [[UIAlertView alloc]
                                 initWithTitle:@"Restore"
                                 message:@"There is no products purchased by you"
                                 delegate:self
                                 cancelButtonTitle:@"Ok"
                                 otherButtonTitles:nil];

    [restorealert show];
}

else
{

    NSLog(@"received restored transactions: %i", queue.transactions.count);

    for (SKPaymentTransaction *transaction in queue.transactions)
    {
        NSString *temp = transaction.payment.productIdentifier;

        NSString *testID = [temp stringByReplacingOccurrencesOfString:projectIdString withString:@""];
        NSString *productID = [testID stringByReplacingOccurrencesOfString:@"." withString:@""]; // remove Dot
        NSLog(@"cutted string is %@",productID);

        [purchasedItemIDs addObject:productID];

        NSLog(@"** Purchased item is %@",purchasedItemIDs);
    }
    HUD.hidden=YES;
    HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
    HUD.labelText = NSLocalizedString(@"Restoring", nil);
    [HUD showWhileExecuting:@selector(restorePurchasedItem) onTarget:self withObject:nil animated:YES];// call the restore Purchase method

  }
   }

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

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

1)这就是它的意思.
只有手动调用restoreCompletedTransactions,才能获得SKPaymentTransactionStateRestored状态的事务. AFAIK,这是为此创建一个按钮(例如,“恢复购买”)的常规做法.

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

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

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

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

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

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

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

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

点赞