Sending data about the receipt of an application purchase on my server

I am implementing a validation validation server for in-app purchases as described in the Check Validation Guide Programming Guide .

Whenever I try to encode a Base64 receipt and send it to my server, I get an error from Apple. But if I manually copy the encrypted base64 on the server, encode it and call REST on Apple, their iTunes server will respond correctly.

I'm not sure what I'm doing wrong on the client side. The code is very simple:

-(NSString*) retrieveReceiptFromCompletedTransaction:(SKPaymentTransaction*)transaction { NSData *receiptData; NSString *receiptString; NSBundle *bundle = [NSBundle mainBundle]; if ([bundle respondsToSelector:@selector(appStoreReceiptURL)]) { NSURL *receiptURL = [bundle performSelector:@selector(appStoreReceiptURL)]; receiptData= [NSData dataWithContentsOfURL:receiptURL]; } else { receiptData = transaction.transactionReceipt; } receiptString = [receiptData base64EncodedStringWithOptions:0]; return receiptString; } 

Any ideas?

+8
ios base64 in-app-purchase
source share
1 answer
  • The approach implemented for the RENEWABLE type has not been tested for other types (May or May may not be useful for other types).
  • Point number 5 (sending a line directly to the server (JAVA) is the way I was able to solve these problems (similar question face to face)
  • I am writing a complete approach to help a beginner too.

  • Create a shared key from your iTunes account.

  • Than in your codes (ios side) use shared_secret #define SHARED_SECRET @ "XXXXXX6666555XXXXXXx"
  • IN

- (void) paymentQueue: (SKPaymentQueue *) queue updatedTransactions: (NSArray *) transactions

  • SKPaymentTransactionStatePurchased

     { ..... case SKPaymentTransactionStatePurchased: if ([transaction.payment.productIdentifier isEqualToString:PRICEPLAN1]) { //[server PurchasedClinicalToDoList]; [self completeTransaction: transaction]; } [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; break; } 

5: GETTING VALIDATE

 - (void) completeTransaction: (SKPaymentTransaction *)transaction { // NSString* receiptString = [[NSString alloc] initWithString:transaction.payment.productIdentifier]; NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; NSData *receipt = [NSData dataWithContentsOfURL:receiptURL]; NSString *jsonObjectString = [receipt base64EncodedStringWithOptions:0]; [self validateViaOwnServer:jsonObjectString]; [self validateDirectly: receipt]; } 

6.ValidateViaServerSideCodes:

  -(void)validateViaOwnServer :(NSString*)receipt { NSString* BASEURl = @"XXXXXXXXX/XXX/XXXX"; NSString *TestReceipt= [BASEURl stringByAppendingString:@"/InApp/iOS/updatePurchase"]; NSDictionary *params = @ {@"receipt" :receipt]}; AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager]; manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"]; manager.responseSerializer = [AFHTTPResponseSerializer serializer]; [manager TestReceipt parameters:params success:^(AFHTTPRequestOperation *operation, id responseData) { } failure:^(AFHTTPRequestOperation *operation, NSError *error) { }]; } 

7. CHECK VALID:

 -(void) validateDirectly :(NSData*)receipt { // Sent to the server by the device // Create the JSON object that describes the request NSError *error; // NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents options:0 error:&error]; NSData *requestData = [NSJSONSerialization dataWithJSONObject:[NSDictionary dictionaryWithObjectsAndKeys: [receipt base64EncodedStringWithOptions:0],@"receipt-data", SHARED_SECRET,@"password", nil] options:NSJSONWritingPrettyPrinted error:&error ]; if(!requestData) { /* ... Handle error ... */ } // Create a POST request with the receipt data. NSURL *storeURL = [NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"]; //@"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) { /* ... Handle error ... */ // NSLog(@"CONNECTION ERROR"); } else { NSError *error; NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (!jsonResponse) { // NSLog(@"NOT JSON"); /* ... Handle error ...*/ } else{ /* ... YES VALIDATED ...*/ }/* ... Send a response back to the device ... */ } }]; } 

8: SERVER HEART CODES (JAVA)

String URL = " https://buy.itunes.apple.com/verifyReceipt ";

  try { URL url = new URL(URL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setDoOutput(true); conn.setRequestMethod("POST"); //conn.setRequestProperty("Content-Type", "text/plain"); conn.setRequestProperty("Accept", "application/json"); conn.setRequestProperty("Content-Type", "application/json"); String input = "{\"receipt-data\": \""+receiptData+"\", \"password\": \"69744THESECRETKEYXXX\"}"; OutputStream os = conn.getOutputStream(); os.write(input.getBytes()); os.flush(); if (conn.getResponseCode() != 200) { throw new RuntimeException("Failed : HTTP error code : " + conn.getResponseCode()); } BufferedReader br = new BufferedReader(new InputStreamReader( (conn.getInputStream()))); String output; System.out.println("Output from Server .... \n"); while ((output = br.readLine()) != null) { appleJson += output; // System.out.println(output); } conn.disconnect(); appleReceipt = gson.fromJson(appleJson, AppleReceipt.class); purchaseStartDate = appleReceipt.getReceipt().getIn_app().get(1).getOriginal_purchase_date_ms(); expiryDate = appleReceipt.getReceipt().getIn_app().get(1).getExpires_date_ms(); // System.out.println("Apple receipt expiry date="+appleReceipt.getReceipt().getIn_app().get(1).getExpires_date_ms()); // System.out.println("Apple receipt expiry date="+appleReceipt.getReceipt().getIn_app().get(1).getExpires_date_ms()); 
+8
source share

All Articles