我一直试图在我的spritekit游戏中实现收据验证。我一直在学习各种教程,基本上以下面的代码结束。
enum RequestURL: String {
case production = "https://buy.itunes.apple.com/verifyReceipt"
case sandbox = "https://sandbox.itunes.apple.com/verifyReceipt"
case myServer = "my server address"
}
enum ReceiptStatusCode: Int {
// Not decodable status
case unknown = -2
// No status returned
case none = -1
// valid status
case valid = 0
// The App Store could not read the JSON object you provided.
case JSONNotReadable = 21000
// The data in the receipt-data property was malformed or missing.
case malformedOrMissingData = 21002
// The receipt could not be authenticated.
case receiptCouldNotBeAuthenticated = 21003
// The shared secret you provided does not match the shared secret on file for your account.
// Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.
case sharedSecretNotMatching = 21004
// The receipt server is currently not available.
case receiptServerUnavailable = 21005
// This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.
// Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.
case subscriptionExpired = 21006
// This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.
case testReceipt = 21007
// This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead.
case productionEnvironment = 21008
}
func validateReceipt(forTransaction transaction: SKPaymentTransaction) {
guard let receiptURL = NSBundle.mainBundle().appStoreReceiptURL else { return }
guard let receipt = NSData(contentsOfURL: receiptURL) else { return }
let receiptData = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
let payload = ["receipt-data": receiptData]
var receiptPayloadData: NSData?
do {
receiptPayloadData = try NSJSONSerialization.dataWithJSONObject(payload, options: NSJSONWritingOptions(rawValue: 0))
}
catch let error as NSError {
print(error.localizedDescription)
return
}
guard let payloadData = receiptPayloadData else { return }
guard let requestURL = NSURL(string: RequestURL.sandbox.rawValue) else { return }
let request = NSMutableURLRequest(URL: requestURL)
request.HTTPMethod = "POST"
request.HTTPBody = payloadData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) in
if let error = error {
print(error.localizedDescription)
return
}
guard let data = data else { return }
do {
let jsonData = try NSJSONSerialization.JSONObjectWithData(data, options: .MutableLeaves) as? NSDictionary
guard let json = jsonData else { return }
// Correct ?
guard let status = json["status"] as? Int where status == ReceiptStatusCode.valid.rawValue else { return }
// Unlock product here?
// Other checks needed?
}
catch let error as NSError {
print(error.localizedDescription)
return
}
}
task.resume()
}这是一个漂亮的锅炉板代码,并按预期工作。我现在的问题是,我不知道如何在最后一步(标记行)验证收据。我想我现在必须带5张左右的支票才能确认收据。我只是不知道他们中的大多数人会如何迅速行动。大多数教程要么是旧的,不包括这一步,要么是没有迅速编写。
如果任何成功使用收据验证的人都能帮助我朝着正确的方向前进,我将不胜感激。非常感谢
更新:
在JSA986I和cbartel给出了很好的答案之后,我把它变成了github上的一个助手。非常感谢你的帮助
发布于 2015-09-03 20:36:56
在那里,您可以将收据作为JSON返回,并可以访问它。即
if parseJSON["status"] as? Int == 0 {
println("Sucessfully returned purchased receipt data")
}会告诉您您是否成功地获得了收据,因为["status"] 0意味着它已被返回,确定
您可以进一步查询和使用收据数据来查找和使用JSON响应中的项。在这里您可以打印最新的收据信息。
if let receiptInfo: NSArray = parseJSON["latest_receipt_info"] as? NSArray {
let lastReceipt = receiptInfo.lastObject as! NSDictionary
// Get last receipt
println("LAST RECEIPT INFORMATION \n",lastReceipt)
}现在您可以使用json数据了。
现在您可以查询这些数据了,在本例中,我们将在JSOn响应的自动续订订阅到期时发现
// Format date
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss VV"
formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX")
// Get Expiry date as NSDate
let subscriptionExpirationDate: NSDate = formatter.dateFromString(lastReceipt["expires_date"] as! String) as NSDate!
println("\n - DATE SUBSCRIPTION EXPIRES = \(subscriptionExpirationDate)")将上述代码张贴在
if let parseJSON = json {
println("Receipt \(parseJSON)")
}发布于 2015-12-14 18:42:53
下面是在苹果指南之后使用Swift 2.1版的解决方案。
苹果也是建议如下
在您的服务器上验证收据时,您的服务器需要能够处理一个产品签名的应用程序,从Apple的测试环境中获取它的收据。推荐的方法是让生产服务器始终首先根据production验证收据。如果错误代码“生产中使用的沙箱收据”验证失败,则使用测试环境进行验证。
validateReceipt(NSBundle.mainBundle().appStoreReceiptURL) { (success: Bool) -> Void in
print(success)
}
private func receiptData(appStoreReceiptURL : NSURL?) -> NSData? {
guard let receiptURL = appStoreReceiptURL,
receipt = NSData(contentsOfURL: receiptURL) else {
return nil
}
do {
let receiptData = receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
let requestContents = ["receipt-data" : receiptData]
let requestData = try NSJSONSerialization.dataWithJSONObject(requestContents, options: [])
return requestData
}
catch let error as NSError {
print(error)
}
return nil
}
private func validateReceiptInternal(appStoreReceiptURL : NSURL?, isProd: Bool , onCompletion: (Int?) -> Void) {
let serverURL = isProd ? "https://buy.itunes.apple.com/verifyReceipt" : "https://sandbox.itunes.apple.com/verifyReceipt"
guard let receiptData = receiptData(appStoreReceiptURL),
url = NSURL(string: serverURL) else {
onCompletion(nil)
return
}
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = receiptData
let task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
guard let data = data where error == nil else {
onCompletion(nil)
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options:[])
print(json)
guard let statusCode = json["status"] as? Int else {
onCompletion(nil)
return
}
onCompletion(statusCode)
}
catch let error as NSError {
print(error)
onCompletion(nil)
}
})
task.resume()
}
public func validateReceipt(appStoreReceiptURL : NSURL?, onCompletion: (Bool) -> Void) {
validateReceiptInternal(appStoreReceiptURL, isProd: true) { (statusCode: Int?) -> Void in
guard let status = statusCode else {
onCompletion(false)
return
}
// This receipt is from the test environment, but it was sent to the production environment for verification.
if status == 21007 {
self.validateReceiptInternal(appStoreReceiptURL, isProd: false) { (statusCode: Int?) -> Void in
guard let statusValue = statusCode else {
onCompletion(false)
return
}
// 0 if the receipt is valid
if statusValue == 0 {
onCompletion(true)
} else {
onCompletion(false)
}
}
// 0 if the receipt is valid
} else if status == 0 {
onCompletion(true)
} else {
onCompletion(false)
}
}
}发布于 2016-09-16 10:05:25
今天,我在这个问题上有麻烦。我参考了这个答案。但是我发现了检查订阅是否过期的新方法。
这是我在目标C中的代码。
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:resData options:0 error:&error];
// this is response from AppStore
NSDictionary *dictLatestReceiptsInfo = jsonResponse[@"latest_receipt_info"];
long long int expirationDateMs = [[dictLatestReceiptsInfo valueForKeyPath:@"@max.expires_date_ms"] longLongValue];
long long requestDateMs = [jsonResponse[@"receipt"][@"request_date_ms"] longLongValue];
isValidReceipt = [[jsonResponse objectForKey:@"status"] integerValue] == 0 && (expirationDateMs > requestDateMs);希望能帮上忙。
https://stackoverflow.com/questions/32291701
复制相似问题