审查来自苹果的消息
“我们发现您的应用错误地实现了收据验证,因此它无法正确区分审核(沙箱)环境和生产环境。这导致对生产服务器的验证查询而不是沙箱收据检查,并且是阻止我们审查您的应用程序”。
我们的查询: 我们正在应用程序中本地验证收据。在订阅问题时,我们会收到收据。应用程序不知道收据是属于沙盒还是生产环境。因此,应用程序最初将收据发送到生产服务器。生产服务器返回 21007 表示收据属于沙箱环境。然后我们将其发送到沙箱环境。您能否澄清此过程是否错误?
订阅成功后获取收据:
-(void)checkReceipt:(NSData *)receipt forProdictId:(NSString *) productid
{
AppDelegate *appDel = [[UIApplication sharedApplication] delegate];
[appDel showProgressViewWithText:@“Please wait...”];
[ReceiptCheck validateReceiptWithData:receipt completionHandler:^(BOOL success,NSString *response)
{
if(success==YES)
{
[self updateReceipt:receipt withResponse:response];
}
else
{
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
[appDelegate hideProgressView];
}
}
}
----------------------------收据验证-------------------- --------------
#import "ReceiptCheck.h"
#import "NSString+Base64.h"
#import "SBJSON.h"
#define SHARED_SECRET @"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
#define RECEIPT_URL_SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"
#define RECEIPT_URL_PRODUCTION @"https://buy.itunes.apple.com/verifyReceipt"
@implementation ReceiptCheck
@synthesize receiptData,completionBlock;
+(ReceiptCheck *)validateReceiptWithData:(NSData *)_receiptData completionHandler:(void(^)(BOOL,NSString *))handler {
ReceiptCheck *checker = [[ReceiptCheck alloc] init];
checker.receiptData=_receiptData;
checker.completionBlock=handler;
[checker checkReceipt];
return checker;
}
-(void)checkReceipt {
// verifies receipt with Apple
NSError *jsonError = nil;
NSString *receiptBase64 = [NSString base64StringFromData:receiptData length:[receiptData length]];
// NSLog(@"Receipt Base64: %@",receiptBase64);
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[NSDictionary dictionaryWithObjectsAndKeys: receiptBase64,@"receipt-data", SHARED_SECRET,@"password", nil] options:NSJSONWritingPrettyPrinted error:&jsonError];
if(jsonError)
{
completionBlock(NO,[jsonError localizedDescription]);
return;
}
NSURL *requestURL = [NSURL URLWithString:RECEIPT_URL_PRODUCTION];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:requestURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:150];
[req setHTTPMethod:@"POST"];
[req setHTTPBody:jsonData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if(conn)
{
receivedData = [[NSMutableData alloc] init];
} else
{
completionBlock(NO,@"Cannot create connection.");
}
}
-(void)checkReceiptSandBox {
// verifies receipt with Apple
NSError *jsonError = nil;
NSString *receiptBase64 = [NSString base64StringFromData:receiptData length:[receiptData length]];
// NSLog(@"Receipt Base64: %@",receiptBase64);
//NSString *jsonRequest=[NSString stringWithFormat:@"{\"receipt-data\":\"%@\"}",receiptBase64];
//NSLog(@"Sending this JSON: %@",jsonRequest);
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:[NSDictionary dictionaryWithObjectsAndKeys: receiptBase64,@"receipt-data", SHARED_SECRET,@"password", nil] options:NSJSONWritingPrettyPrinted error:&jsonError];
//NSLog(@"JSON: %@",[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] );
if(jsonError)
{
completionBlock(NO,[jsonError localizedDescription]);
return;
}
NSURL *requestURL = [NSURL URLWithString:RECEIPT_URL_SANDBOX];
NSMutableURLRequest *req = [[NSMutableURLRequest alloc] initWithURL:requestURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:150];
[req setHTTPMethod:@"POST"];
[req setHTTPBody:jsonData];
NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self];
if(conn)
{
receivedData = [[NSMutableData alloc] init];
} else
{
completionBlock(NO,@"Cannot create connection.");
}
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
completionBlock(NO,[error localizedDescription]);
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
[receivedData setLength:0];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
[receivedData appendData:data];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSString *response = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];
NSData* data = [response dataUsingEncoding:NSUTF8StringEncoding];
NSString *json_string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
SBJSON *parser = [[SBJSON alloc] init];
NSDictionary *values = [parser objectWithString:json_string error:nil];
if([values valueForKey:@"status"])
{
if([[values valueForKey:@"status"] integerValue] == 21007)
{ // SAND BOX RECEIPT
[self checkReceiptSandBox];
return;
}
}
completionBlock(YES,response);
}
@end
更新收据后:
- (void) updateReceipt:(NSData *)receipt withResponse:(NSString *)response
{
NSData* data = [response dataUsingEncoding:NSUTF8StringEncoding];
NSString *json_string = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
SBJSON *parser = [[SBJSON alloc] init];
NSDictionary *values = [parser objectWithString:json_string error:nil];
NSLog(@"%@",values);
if([[values valueForKey:@"status"] integerValue] == 0)
{
NSString *strReceipt=@"";
if([values valueForKey:@"latest_receipt"])
{
strReceipt = [values valueForKey:@"latest_receipt"];
if([values valueForKey:@"latest_receipt_info"])
{
[self saveReceiptDetailsWithReceipt:strReceipt andReceiptInfo:values];
NSString *strProductID = [[values valueForKey:@"latest_receipt_info"] valueForKey:@"product_id"];
NSLog(@"%@",strProductID);
WebServices *webService = [[WebServices alloc] init];
webService.delegate=self;
AppDelegate *appDel = [[UIApplication sharedApplication] delegate];
[appDel showProgressViewWithText:@"Please wait..."];
webService.strSubscriptionProductID=strProductID;
[webService afterSubscription:values andSubscriptionId:[self getSubscriptionIDForProductID:strProductID] receipt:strReceipt];
}
}
}
else if([[values valueForKey:@"status"] integerValue] == 21006)
{
NSString *strReceipt=[NSString base64StringFromData:receipt length:[receipt length]];
if([values valueForKey:@"latest_expired_receipt_info"])
{
[self saveReceiptDetailsWithReceipt:strReceipt andReceiptInfo:values];
}
}
else if([[values valueForKey:@"status"] integerValue] == 21000)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"JSON Error" message:[NSString stringWithFormat:@"The App Store could not read the JSON object you provided."] delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
}
else if([[values valueForKey:@"status"] integerValue] == 21002)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Data Error" message:[NSString stringWithFormat:@"The data in the receipt-data property was malformed."] delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
}
else if([[values valueForKey:@"status"] integerValue] == 21003)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Receipt Authentication Error" message:[NSString stringWithFormat:@"The receipt could not be authenticated."] delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
}
else if([[values valueForKey:@"status"] integerValue] == 21004)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Shared Secret Error" message:[NSString stringWithFormat:@"The shared secret you provided does not match the shared secret on file for your account."] delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
}
else if([[values valueForKey:@"status"] integerValue] == 21005)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Server Error" message:[NSString stringWithFormat:@"The receipt server is not currently available."] delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
}
else if([[values valueForKey:@"status"] integerValue] == 21007)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Receipt Error" message:[NSString stringWithFormat:@"This receipt is a sandbox receipt, but it was sent to the production service for verification."] delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
}
else if([[values valueForKey:@"status"] integerValue] == 21008)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Receipt Error" message:[NSString stringWithFormat:@"This receipt is a production receipt, but it was sent to the sandbox service for verification."] delegate:nil cancelButtonTitle:@"Close" otherButtonTitles:nil];
[alert show];
}
}