我正在将应用程序从iOS6转换为iOS7。在我使用已弃用的 transactionReceipt
方法之前,现在我正在尝试推荐的方法来检索收据,然后以 base 64 编码:
NSData *working = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];
// Tried 64 or 76 chars/line and LF or CR line endings
NSString *receipt = [working base64EncodedStringWithOptions:kNilOptions];
以上是代码中唯一的更改。以下是我验证它的方式,没有变化:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue,
^{
NSMutableString *url = [NSMutableString string];
[url appendFormat:@"%@", WEB_SERVICE];
[url appendFormat:@"receipt=%@", receipt];
NSStringEncoding encoding;
NSError *error = [NSError new];
NSURL *URL = [NSURL URLWithString:url];
NSString *json = [NSString stringWithContentsOfURL:URL usedEncoding:&encoding error:&error];
// check json and error
// ... code omitted
}
在服务器端,这是我用来验证收据的 PHP 代码,除了尝试沙箱以查找任何错误外,没有任何变化:
// Encode as JSON
$json = json_encode(array('receipt-data' => $receipt));
// Try production first, if it doesn't work, then try the sandbox
$working = postJSONToURL('https://buy.itunes.apple.com/verifyReceipt', $json, false);
error_log('production - '.print_r($working, true));
if (@$working['status'] !== 0) // === 21007)
$working = postJSONToURL('https://sandbox.itunes.apple.com/verifyReceipt', $json, true);
error_log('sandbox - '.print_r($working, true));
这是错误日志输出:
production - Array'n('n [status] => 21002'n [exception] => java.lang.IllegalArgumentException'n)'n
sandbox - Array'n('n [status] => 21002'n [exception] => java.lang.IllegalArgumentException'n)'n
看起来我正在向苹果抛出各种例外!
同样,唯一的区别是如何检索和编码收据。有没有人遇到过这个问题并修复了它?
感谢您的阅读。
/年
根据要求,PostJSONToURL 的代码:
function postJSONToURL($url, $json, $disableSSLVerify = false)
{
$resource = curl_init($url);
curl_setopt($resource, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($resource, CURLOPT_POSTFIELDS, $json);
curl_setopt($resource, CURLOPT_RETURNTRANSFER, true);
curl_setopt($resource, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: '.strlen($json)));
curl_setopt($resource, CURLOPT_HEADER, 0);
if ($disableSSLVerify)
{
curl_setopt($resource, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($resource, CURLOPT_SSL_VERIFYPEER, 0);
}
//curl_setopt($resource, CURLOPT_VERBOSE, true);
//curl_setopt($resource, CURLOPT_STDERR, $fp = fopen('/tmp/curl_output'.rand(1000, 9999).'.txt', 'w'));
$contents = json_decode(curl_exec($resource), true);
if (!$contents)
$contents = array();
curl_close($resource);
//fclose($fp);
return $contents;
}
经过一些实验后的新细节已经确定,以base 64编码发送现有数据可能会侵犯某些内部限制。如果超过某个内部限制,则甚至不会发送数据,它会在设备上本地失败,低于此限制,则会发送。列有:数据格式、编码数据大小、是否到达服务器:
raw receipt data 5K N/A
base64 no options 6.66K yes
base64 76 chars/line 6.75K no
base64 64 chars/line 6.77K no
hex coded 10K no
请注意,成功发送和不发送之间的差异小于 100 字节。
我遇到了这个问题,到处找,包括苹果的开发论坛。苹果会给出几个股票回复,仅此而已。我认为这是苹果方面的一个错误。设备上的本地验证将起作用,因此请尝试转换为该验证。如果您绝对必须使用服务器端验证,那么现在似乎只有transactionReceipt
有效。
该功能刚刚被弃用,没有被禁止,所以我只会使用它并希望苹果批准该应用程序。事实上,这就是我刚刚所做的,手指交叉,等待批准。
您可以在 Xcode 中关闭警告,方法是将代码括起来,如下所示:
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
// code using transactionReceipt
#pragma clang diagnostic pop
我在使用iOS7收据方面取得了成功,该收据使用以下方法从应用程序包中获得:
NSURL *receiptURL = [[NSBundle mainBundle] performSelector:@selector(appStoreReceiptURL)];
receipt = [NSData dataWithContentsOfURL:receiptURL];
从Apple的服务器到iOS7样式的收据对我的服务器的响应与以前的收据样式有很大不同。下面是一个经过验证的收据示例:
{"status":0,
"environment":"Sandbox",
"receipt":
{"receipt_type":"ProductionSandbox",
"adam_id":0,
"bundle_id":"<snip>",
"application_version":"1.0",
"download_id":0,
"request_date":"2013-11-12 01:43:06 Etc'/GMT",
"request_date_ms":"1384220586352",
"request_date_pst":"2013-11-11 17:43:06 America'/Los_Angeles",
"in_app":[
{"quantity":"1",
"product_id":"<snip>",
"transaction_id":"1000000092978110",
"original_transaction_id":"1000000092978110",
"purchase_date":"2013-11-12 01:36:49 Etc'/GMT",
"purchase_date_ms":"1384220209000",
"purchase_date_pst":"2013-11-11 17:36:49 America'/Los_Angeles",
"original_purchase_date":"2013-11-12 01:36:49 Etc'/GMT",
"original_purchase_date_ms":"1384220209000",
"original_purchase_date_pst":"2013-11-11 17:36:49 America'/Los_Angeles",
"is_trial_period":"false"}
]
}
}
漂亮的印痕是为了我的利益,而不是严格来说苹果给出的。
这是我客户端的胆量:
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters addEntriesFromDictionary:[credentials dictionary]];
// receipt is an object of my own making, but base64String just returns an
// NSString representation of the receipt data.
parameters[PURCHASE_RECEIPT] = [receipt base64String];
NSURLRequest *request =
[[AFHTTPRequestSerializer serializer]
requestWithMethod:@"POST"
URLString:urlString
parameters:parameters];
AFHTTPRequestOperation *operation =
[[AFHTTPRequestOperation alloc]
initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
<snip>
[operation start];
以下是我在服务器端使用的内容的胆量,其中 URL 是生产或沙盒验证服务器:
// Some code from http://stackoverflow.com/questions/5647461/how-do-i-send-a-post-request-with-php
private static function validateReceipt($receiptData, $URL) {
// Connect to Apple server and validate.
$data = json_encode(array("receipt-data" => $receiptData));
// use key 'http' even if you send the request to https://...
// This: 'content' => http_build_query($data),
// seems to generate an error (21002)
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded",
'method' => 'POST',
'content' => $data
),
);
$context = stream_context_create($options);
$result = file_get_contents($URL, false, $context);
//Utils::writeToLog("done validateReceipt: " . $result);
// See http://php.net/manual/en/function.file-get-contents.php
// for the use of === comparison.
if ($result === FALSE) {
return NULL;
} else {
// Decode the result as an associative array.
return json_decode($result, true);
}
}
我在iOS6和iOS7样式收据上都成功使用此代码。
我有同样的症状:错误 21002(java.lang.IllegalArgumentException(,同时验证来自我自己的服务器的 io7 样式收据。
事实证明有两个问题:
-
我的收据数据错误。 不知何故,在将数据传递到我的服务器时,它最终在 base64 编码的收据数据中出现了一堆"''r'"字符。 (我用一些搜索和替换代码去除了这些(。
-
如果您使用的是自动续订订阅,则必须在 JSON 有效负载中传入两个参数来验证收据:"收据数据"和"密码",这应该是您在 iTunes Connect 中的共享密钥。
一旦我解决了这两件事,我的验证收据 http 请求按预期工作。
Apple 使用 RFC 4648 中的 url 和文件名 safe base64,其中 -_ 作为最后两个字符。 +/是许多实现的典型特征。
OP 的代码仅适用于 10.9+ 或 7.0+,这是一个以前私有的 API,允许支持 4.0+ 和 10.6+:
[NSData base64Encoding]