Search code examples
iosreceipt-validation

How to test receipt validation in this case?


I am working on converting an app from paid to free, with some of the former features under IAP. As a result, existing users need to have a copy of the IAP. In order to do this, I am using receipt validation code from Apple's Website. My goal in this case is not to actually validate the receipt for legitimacy, but instead to get back the version number that the user bought so I can detect if they are a paid user (thank you to this question for the suggestion).

NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
if (!receipt) { NSLog(@"No receipt found"); return; }

This is the code I am using to get the user's receipt. It is near-identical to the code on the above official apple site. However, I still want to test it and the code following it, which grants the user their IAP.

However, the above code will log "No receipt found" and return if I run the program in the Simulator, on my iPhone via Xcode, or on my iPhone via TestFlight. I installed the current App Store version, then tried TestFlight, and it still gave the same no-receipt error.

How do I get a copy of the receipt for testing, and moreover, how would I test this form of receipt validation?


Solution

  • SKReceiptRefreshRequest will provide a fake receipt, which you validate on apple's sandbox validation server. Calling SKReceiptRefreshRequest was the element I was missing.

    SKReceiptRefreshRequest *receiptRequest = [[SKReceiptRefreshRequest alloc] initWithReceiptProperties:nil];
    receiptRequest.delegate = self;
    [receiptRequest start];
    

    -

    - (void)requestDidFinish:(SKRequest *)request {
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
    if (!receipt) { NSLog(@"No receipt found"); return; }
    // Create the JSON object that describes the request
    NSError *error;
    NSDictionary *requestContents = @{
                                      @"receipt-data": [receipt base64EncodedStringWithOptions:0]
                                      };
    NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
                                                          options:0
                                                            error:&error];
    
    if (!requestData) { NSLog(@"No request data found"); return; }
    
    // Create a POST request with the receipt data.
    NSURL *storeURL = [NSURL URLWithString:@"https://sandbox.itunes.apple.com/verifyReceipt"];
    NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
    [storeRequest setHTTPMethod:@"POST"];
    [storeRequest setHTTPBody:requestData];
    // Make a connection to the iTunes Store on a background queue.
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
                               if (connectionError) {
                                   NSLog(@"Connection error");
                                   return;
                               } else {
                                   NSError *error;
                                   NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
                                   if (!jsonResponse) { return; }
                                   NSLog(@"JsonResponce: %@",jsonResponse);
                                   NSString *version = jsonResponse[@"receipt"][@"original_application_version"];
                                   //found version number! Do whatever with it!
                               }
                           }];