我尝试在服务器端使用收据验证。一切都很好,但有时我看到很奇怪:10次验证是可以的,但在11我得到21002错误。我不知道该怎么办。有时,我在启动应用程序后第一次验证收据时会收到错误21002。
App方面:
func validateReceipt(productID: String) {
let receipt = NSData(contentsOfURL: NSBundle.mainBundle().appStoreReceiptURL!)!
let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
let request = NSMutableURLRequest(URL: NSURL(string: "my_server_url")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "POST"
request.HTTPBody = receiptdata.dataUsingEncoding(NSUTF8StringEncoding)
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let json = try! NSJSONSerialization.JSONObjectWithData(data!, options: .MutableLeaves) as? NSDictionary
if (error != nil) {
print(error!.localizedDescription)
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Error could not parse JSON: '\(jsonStr)'")
}
else {
if let parseJSON = json {
if String(parseJSON["status"]! == "ok" {
//do something
print("Validate OK")
}else{
print("Validate NOK")
}
}
else {
let jsonStr = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("Receipt Error: \(jsonStr)")
}
}
})
task.resume()
}
服务器端php脚本:
function getReceiptData($receipt)
{
$endpoint = 'https://sandbox.itunes.apple.com/verifyReceipt';
$ch = curl_init($endpoint);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $receipt);
$response = curl_exec($ch);
$errno = curl_errno($ch);
$errmsg = curl_error($ch);
curl_close($ch);
$msg = $response.' - '.$errno.' - '.$errmsg;
echo $response;
}
foreach ($_POST as $key=>$value){
$newcontent .= $key.' '.$value;
}
$new = trim($newcontent);
$new = trim($newcontent);
$new = str_replace('_','+',$new);
$new = str_replace(' =','==',$new);
if (substr_count($new,'=') == 0){
if (strpos('=',$new) === false){
$new .= '=';
}
}
$new = '{"receipt-data":"'.$new.'"}';
$info = getReceiptData($new);
我根据示例http://www.brianjcoleman.com/tutorial-receipt-validation-in-swift/
做的所有事情所以,有时我觉得应用程序发送到服务器端错误的收据和PHP脚本无法解析它,我收到21002错误状态。有什么建议吗?
答案 0 :(得分:6)
尝试从receipt
中删除字符' \ n'和' \ r'并取代' +'与'%2B'在将其发送到服务器之前。像这样:
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]];
答案 1 :(得分:2)
代码21002表示您发送给具有共享密钥和收据数据的苹果的JSON是"错误的"或者不是苹果想要的格式。
这就是我做的(目标C和本地验证)
#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];
}
答案 2 :(得分:2)
关于NSDataBase64EncodingOptions的全部内容。使用EncodingEndLineWithCarriageReturn
类型代替0
。
只需更改此行
即可let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
到这一行
let receiptdata = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
我自己尝试了这个并且有效。
答案 3 :(得分:0)
这已经很晚了所以你现在可能已经解决了这个问题 - 但是我注意到了一个错字 - 你遗漏了一个")"在condition == "ok"
:
if let parseJSON = json {
if String(parseJSON["status"]! == "ok" {
//do something
答案 4 :(得分:0)
收据数据已被base64编码。请参阅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;
}