客户端IAP二次验证
阅读原文时间:2023年07月10日阅读:2

1、首先苹果IAP把每次购买抽象成了一个事务(SKPaymentTransaction),

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response;
每次在上述方法中收到反馈信息之后添加的[[SKPaymentQueue defaultQueue] addPayment:payment];
就相当于在事务管理中添加了一个事务,只有事务被正常结束(finishTransaction:)该次支付行为才算完成。
即使一次支付中途被中断,这次事务也并没有丢失。假设支付没有完成App就退出了(比如突然崩溃了),那么当下次App重启之后(调用了addTransactionObserver:),之前被中断的事务会接着进行。
这个的缺点就是中间等待重启的时间可能会很长,影响用户体验。

2、在购买成功后的客户端二次验证。

每次购买成功之后都会把encodeStr存到本地,验证成功再进行删除。以后每次打开应用或打开充值会先查看是否有未完成的验证

//交易结果

  • (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
    NSLog(@"5.交易结果");
    for (SKPaymentTransaction *transaction in transactions){
    switch (transaction.transactionState){
    case SKPaymentTransactionStatePurchased:{//交易完成
    NSLog(@"交易完成");
    [self completeTransaction:transaction];
    } break;
    case SKPaymentTransactionStateFailed://交易失败
    { [self failedTransaction:transaction];
    NSLog(@"-----交易失败 --------");
    [SVProgressHUD dismiss];
    UIAlertView *alerView2 = [[UIAlertView alloc] initWithTitle:@"提示"
    message:@"购买失败,请重新尝试购买"
    delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
    [alerView2 show];

        }break;  
        case SKPaymentTransactionStateRestored://已经购买过该商品  
            \[self restoreTransaction:transaction\];  
            NSLog(@"-----已经购买过该商品 --------");  
        case SKPaymentTransactionStatePurchasing:      //商品添加进列表  
            NSLog(@"-----商品添加进列表 --------");  
            break;  
        default:  
            break;  
    }  

    }
    }

  • (void)completeTransaction: (SKPaymentTransaction *)transaction{
    NSString * productIdentifier = transaction.payment.productIdentifier;
    if ([productIdentifier length] > 0) {
    [SVProgressHUD dismiss];
    //添加IAPModel到本地
    //获取验证凭证
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    //从沙盒中获取购买凭证
    NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
    //进行Base64加密
    NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
    WekeIAPModel *model = [[WekeIAPModel alloc]initWithReceiptStr:encodeStr user_id:[AppSingle sharedAppSingle].user_id];
    [[AppSingle sharedAppSingle].IAPArray addObject:model];
    [SaveCachesFile saveDataList:[AppSingle sharedAppSingle].IAPArray fileName:WekeIAP];
    [self verifyPruchaseWithEncodeStr:encodeStr];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    }else{
    [SVProgressHUD dismiss];
    UIAlertView *alerView2 = [[UIAlertView alloc] initWithTitle:@"提示"
    message:@"购买失败,未能连接到苹果服务器"
    delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
    [alerView2 show];
    }
    }
    //验证购买凭证

  • (void)verifyPruchaseWithEncodeStr :(NSString *)encodeStr{
    //验证URL POST请求
    NSURL *url = [NSURL URLWithString:Buy_Verify_Receipt_Url];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0f];
    request.HTTPMethod = @"POST";
    NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
    request.HTTPBody = payloadData;
    // 提交验证请求,并获得官方的验证JSON结果
    NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    // 官方验证结果为空
    if (result == nil) {
    NSLog(@"验证失败");
    }else{
    NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
    NSLog(@"线上环境验证结果%@",dict);
    if ([[dict objectForKey:@"status"] integerValue] == 21007) {
    //如果是沙盒环境
    [self verifyPruchaseInSANDBOXWithEncodeStr:encodeStr];
    }else if ([[dict objectForKey:@"status"] integerValue] == 0){
    NSLog(@"线上环境验证成功,进行增加积分等操作");
    //验证成功 删除IAP数组中的该Model
    for (WekeIAPModel *model in self.IAPArray) {
    if ([model.encodeStr isEqualToString:encodeStr]) {
    [[AppSingle sharedAppSingle].IAPArray removeObject:model];
    [self.IAPArray removeObject:model];
    [SaveCachesFile saveDataList:[AppSingle sharedAppSingle].IAPArray fileName:WekeIAP];
    }
    }
    [self postGrede];

    }else{  
        NSLog(@"线上环境验证失败");  
        UIAlertController \*alertCT = \[UIAlertController alertControllerWithTitle:@"提示" message:@"充值验证失败,请重试" preferredStyle:(UIAlertControllerStyleAlert)\];  
        UIAlertAction \*cancel = \[UIAlertAction actionWithTitle:@"取消"style:UIAlertActionStyleCancel handler:^(UIAlertAction \* \_Nonnull action) {  
        }\];  
        UIAlertAction \*care = \[UIAlertAction actionWithTitle:@"重试"style:UIAlertActionStyleDefault handler:^(UIAlertAction \* \_Nonnull action) {  
            \[self verifyPruchaseWithEncodeStr:encodeStr\];  
        }\];  
        \[alertCT addAction:cancel\];  
        \[alertCT addAction:care\];  
        \[self presentViewController:alertCT animated:YES completion:nil\];  
    }  

    }
    }

//在沙盒中验证

  • (void)verifyPruchaseInSANDBOXWithEncodeStr:(NSString *)encodeStr{

    //验证URL POST请求
    NSURL *url = [NSURL URLWithString:SANDBOX_VERIFY_RECEIPT_URL];
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0f];
    request.HTTPMethod = @"POST";
    NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
    NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
    request.HTTPBody = payloadData;
    // 提交验证请求,并获得官方的验证JSON结果
    NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
    if (result== nil) {
    NSLog(@"沙盒验证失败");
    UIAlertController *alertCT = [UIAlertController alertControllerWithTitle:@"提示" message:@"充值验证失败,请重试" preferredStyle:(UIAlertControllerStyleAlert)];
    UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消"style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
    }];
    UIAlertAction *care = [UIAlertAction actionWithTitle:@"重试"style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
    [self verifyPruchaseInSANDBOXWithEncodeStr:encodeStr];
    }];
    [alertCT addAction:cancel];
    [alertCT addAction:care];
    [self presentViewController:alertCT animated:YES completion:nil];
    }else{
    NSLog(@"沙盒验证成功");
    [self postGrede];
    //验证成功 删除IAP数组中的该Model
    for (WekeIAPModel *model in self.IAPArray) {
    if ([model.encodeStr isEqualToString:encodeStr]) {
    [[AppSingle sharedAppSingle].IAPArray removeObject:model];
    [self.IAPArray removeObject:model];
    [SaveCachesFile saveDataList:[AppSingle sharedAppSingle].IAPArray fileName:WekeIAP];
    }
    }

    }
    }

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章