4

我正在使用 ios 进行应用程序购买,我几乎没有疑问,这些疑问将有助于像我这样的新手,所以了解应用程序购买。

1)如果用户“如果他之前删除了我的应用程序,则将我的应用程序安装到新设备或同一设备中”,我的应用程序出现问题,当时用户尝试购买已购买的项目,我的代码restoreTransaction在 switch case 中没有调用updatedTransactions

我收到消息,you ve already purchased this tap okay to downlaod it FREE Enviornment sandbox它调用了这个SKPaymentTransactionStatePurchased案例,但它没有调用SKPaymentTransactionStateRestored我的案例中的问题..

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

2) 购买商品时只询问一次密码,之后不再询问购买密码。它直接显示带有确认按钮的对话框,但我的项目经理说它应该为每次购买商品询问密码。

每次我尝试恢复购买时它都会要求输入密码..奇怪。

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

  }
   }
4

2 回答 2

2

恕我直言,如果有不同的问题,您最好将这个问题剪裁一些。

无论如何,我会尝试回答:

1)这就是它的意思。当您手动调用时,您才会获得带有SKPaymentTransactionStateRestored状态的交易。AFAIK,这是为此创建一个按钮(例如,“恢复购买”)的正常做法。restoreCompletedTransactions

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 的沙盒服务器。

于 2013-08-10T10:17:12.747 回答
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];
        }
   }

快乐编码..

于 2013-08-09T12:18:40.293 回答