IOS receipt validation error 21002

前端 未结 5 477
旧巷少年郎
旧巷少年郎 2021-01-01 03:01

I\'m trying to use receipt validation with my server side. Everything is ok, but sometimes I see strange: 10 times validation is OK, but on 11 i get 21002 error. I dont know

相关标签:
5条回答
  • 2021-01-01 03:20

    Try removing from receipt the characters '\n' and '\r' and replacing '+' with'%2B' before sending it to the server. Something like this:

     NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
     NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
     NSString *receiptDataString = [receipt base64EncodedStringWithOptions:0];
     receiptDataString=[receiptDataString stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
     receiptDataString=[receiptDataString stringByReplacingOccurrencesOfString:@"\n" withString:@""];
     receiptDataString=[receiptDataString stringByReplacingOccurrencesOfString:@"\r" withString:@""];
     NSString *postDataString = [NSString stringWithFormat:@"receipt-data=%@", receiptDataString];
     NSString *length = [NSString stringWithFormat:@"%lu", (unsigned long)[postDataString length]];
     [request setValue:length forHTTPHeaderField:@"Content-Length"];
     [request setHTTPBody:[postDataString dataUsingEncoding:NSASCIIStringEncoding]];
    
    0 讨论(0)
  • 2021-01-01 03:25

    This is late so you might well have solved this now - but i noticed a typo - you left out a ")" where you cast to a string in the condition == "ok":

    if let parseJSON = json {
        if String(parseJSON["status"]! == "ok" {
        //do something
    
    0 讨论(0)
  • 2021-01-01 03:26

    The Receipt Data is already base64 encoded. Refer to Receipt Validation Programming Guide

    $receipt_data = "MII.................KY\/6oc9w==";
    
    $data = "{\"receipt-data\":\"$receipt_data\"}";
    
    $url = "https://buy.itunes.apple.com/verifyReceipt";        // if use this to test sandbox will return "{"status":21007}"
    //$url = "https://sandbox.itunes.apple.com/verifyReceipt";  // for sandbox
    
    var_dump(post($url,$data));
    
    function post($url, $data, $headerArray = array())
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,FALSE);
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        if (array() === $headerArray)
            curl_setopt($curl, CURLOPT_HTTPHEADER,["Content-type:application/json;charset='utf-8'","Accept:application/json"]);
    
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }
    
    0 讨论(0)
  • 2021-01-01 03:29

    Code 21002 means that the JSON you are sending to apple which has your shared secret and your receipt data is "misformed" or not in the format apple wants it.

    Here is a screenshot with the subsequent error codes and their meaning

    This is how i did it (Objective C and Local Validation)

      #define kAppReceipt @"LATEST_RECEIPT"
      #define kStoreKitSecret @"YOUR SHARED SECRET"
      #define kSandboxServer @"https://sandbox.itunes.apple.com/verifyReceipt"
    
    -(void)loadProducts{
     NSError *error;
    
    if(![[NSUserDefaults standardUserDefaults]objectForKey:kAppReceipt]){
        NSURL *recieptURL  = [[NSBundle mainBundle]appStoreReceiptURL];
        NSError *recieptError ;
        BOOL isPresent = [recieptURL checkResourceIsReachableAndReturnError:&recieptError];
        if(!isPresent){
            return;
        }
    
        NSData *recieptData = [NSData dataWithContentsOfURL:recieptURL];
        if(!recieptData){
            return;
        }
    
        payLoad = [NSMutableDictionary dictionaryWithObject:[recieptData base64EncodedStringWithOptions:0] forKey:@"receipt-data"];
    }
    else {
        [payLoad setObject:[[NSUserDefaults standardUserDefaults]objectForKey:kAppReceipt] forKey:@"receipt-data"];
    }
    
    
    [payLoad setObject:kStoreKitSecret forKey:@"password"];
    
    NSData *requestData = [NSJSONSerialization dataWithJSONObject:payLoad options:0 error:&error];
    
    NSMutableURLRequest *sandBoxReq = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:kSandboxServer]];
    [sandBoxReq setHTTPMethod:@"POST"];
    [sandBoxReq setHTTPBody:requestData];
    
    
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    [[session dataTaskWithRequest:sandBoxReq completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    
        if(!error){
            NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
            NSString * latestReceipt = [jsonResponse objectForKey:@"latest_receipt"];
    
           // this is the latest receipt that you should store in NSUSER DEFAULT to then later sent this same receipt when you make this same call
            [[NSUserDefaults standardUserDefaults] setObject:latestReceipt forKey:kAppReceipt];
        }
    
      }] resume];
    }
    
    0 讨论(0)
  • 2021-01-01 03:43

    It's all about the NSDataBase64EncodingOptions. Use type EncodingEndLineWithCarriageReturn instead of 0.

    Simply change this line

    let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
    

    to this line

    let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
    

    I tried this myself and it worked.

    0 讨论(0)
提交回复
热议问题