我的应用程序仅在 App Store 上崩溃!似乎与 IAP 收据验证有关
My app only crashes on App Store! Seems related to IAP receipt validation
我发布了我的游戏更新,我认为它可以修复 IAP 的收据验证。
这在我的开发环境中运行良好,但如果您从应用商店下载该应用,它会在启动时崩溃。我查看了设备上的崩溃报告,但我无法确切地说出我犯了哪个错误,因为如果我从我的计算机上构建,这一切都会完美无缺。非常令人沮丧的是,当我的应用程序在启动时崩溃时,Apple 会接受我的更新!
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread: 3
Last Exception Backtrace:
0 CoreFoundation 0x1845a259c __exceptionPreprocess + 132
1 libobjc.A.dylib 0x194cf40e4 objc_exception_throw + 60
2 CoreFoundation 0x184487904 -[__NSArrayI objectAtIndex:] + 224
3 Kill Sector 0x1000b3714 0x10001c000 + 620308
4 CFNetwork 0x183f8af34 __67+[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]_block_invoke_2 + 188
5 Foundation 0x18545b4a8 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16
6 Foundation 0x1853acc34 -[NSBlockOperation main] + 96
7 Foundation 0x18539c5bc -[__NSOperationInternal _start:] + 636
8 Foundation 0x18545e20c __NSOQSchedule_f + 228
9 libdispatch.dylib 0x19533936c _dispatch_client_callout + 16
10 libdispatch.dylib 0x1953434c0 _dispatch_queue_drain + 1216
11 libdispatch.dylib 0x19533c474 _dispatch_queue_invoke + 132
12 libdispatch.dylib 0x195345224 _dispatch_root_queue_drain + 664
13 libdispatch.dylib 0x19534675c _dispatch_worker_thread3 + 108
14 libsystem_pthread.dylib 0x1955152e4 _pthread_wqthread + 816
15 libsystem_pthread.dylib 0x195514fa8 start_wqthread + 4
这是我的支票收据代码:
func checkReceipt(){
var appStoreURL = "https://buy.itunes.apple.com/verifyReceipt"
#if DEBUG
appStoreURL = "https://sandbox.itunes.apple.com/verifyReceipt"
#endif
var appStoreStatusZero = false // we connected to correct app store
if let url = NSBundle.mainBundle().appStoreReceiptURL {
if let receipt = NSData(contentsOfURL: url) {
var error: NSError?
let requestContents = ["receipt-data": receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))]
let requestData = NSJSONSerialization.dataWithJSONObject(requestContents, options: NSJSONWritingOptions(rawValue: 0), error: &error)
if requestData == nil {
println("not receiving request Data")
}
let storeURL = NSURL(string: appStoreURL)
let storeRequest = NSMutableURLRequest(URL: storeURL!)
storeRequest.HTTPMethod = "POST"
storeRequest.HTTPBody = requestData
let queue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(storeRequest, queue: queue, completionHandler: {
response, data, error in
if error != nil {
println("connection error")
return
} else {
var error: NSError?
let jsonResponse = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0), error: &error) as NSDictionary?
if jsonResponse == nil {
println("json error")
return
} else {
var receiptInfo = jsonResponse?.objectForKey("receipt") as NSDictionary?
var inAppInfo = receiptInfo?.objectForKey("in_app") as NSArray?
var thisIAPInfo = inAppInfo?.objectAtIndex(0) as NSDictionary?
var removeAdsID = thisIAPInfo?.objectForKey("product_id") as String?
if removeAdsID == self.productID {
self.adsRemoved = true
}
}
}
})
}
}
}
我在这里做的有什么明显的错误吗?我不知道哪里错了。
有什么方法可以像在应用商店上一样进行测试吗?我尝试过临时部署,但我的应用程序运行良好。在无法测试的情况下很难判断我是否修复了错误!
首先,您永远不应该直接从设备上使用 Apple 服务器验证收据。这不是很安全。您应该选择本地收据验证,或者您的服务器收据验证,以防与苹果验证服务器通信。
我认为您的代码正在崩溃,因为您没有检查这些语句的结果。在某个地方你变得零和崩溃。
var receiptInfo = jsonResponse?.objectForKey("receipt") as NSDictionary?
var inAppInfo = receiptInfo?.objectForKey("in_app") as NSArray?
var thisIAPInfo = inAppInfo?.objectAtIndex(0) as NSDictionary?
var removeAdsID = thisIAPInfo?.objectForKey("product_id") as String?
尝试使用if let
结构。并在获取元素之前检查数组边界,它可能是空的。
类似的东西:
if let receiptInfo = jsonResponse.objectForKey("receipt") as NSDictionary? {
if let inAppInfo = receiptInfo.objectForKey("in_app") as NSArray? {
if (inAppInfo.count > 0) {
if let thisIAPInfo = inAppInfo.objectAtIndex(0) as? NSDictionary {
if let removeAdsID = thisIAPInfo.objectForKey("product_id") as String? {
// Do what you want here
}
}
}
}
}
要了解如何让它更漂亮,您可以阅读以下内容:
http://blog.scottlogic.com/2014/12/08/swift-optional-pyramids-of-doom.html
我发布了我的游戏更新,我认为它可以修复 IAP 的收据验证。
这在我的开发环境中运行良好,但如果您从应用商店下载该应用,它会在启动时崩溃。我查看了设备上的崩溃报告,但我无法确切地说出我犯了哪个错误,因为如果我从我的计算机上构建,这一切都会完美无缺。非常令人沮丧的是,当我的应用程序在启动时崩溃时,Apple 会接受我的更新!
Exception Type: EXC_CRASH (SIGABRT)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Triggered by Thread: 3
Last Exception Backtrace:
0 CoreFoundation 0x1845a259c __exceptionPreprocess + 132
1 libobjc.A.dylib 0x194cf40e4 objc_exception_throw + 60
2 CoreFoundation 0x184487904 -[__NSArrayI objectAtIndex:] + 224
3 Kill Sector 0x1000b3714 0x10001c000 + 620308
4 CFNetwork 0x183f8af34 __67+[NSURLConnection sendAsynchronousRequest:queue:completionHandler:]_block_invoke_2 + 188
5 Foundation 0x18545b4a8 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 16
6 Foundation 0x1853acc34 -[NSBlockOperation main] + 96
7 Foundation 0x18539c5bc -[__NSOperationInternal _start:] + 636
8 Foundation 0x18545e20c __NSOQSchedule_f + 228
9 libdispatch.dylib 0x19533936c _dispatch_client_callout + 16
10 libdispatch.dylib 0x1953434c0 _dispatch_queue_drain + 1216
11 libdispatch.dylib 0x19533c474 _dispatch_queue_invoke + 132
12 libdispatch.dylib 0x195345224 _dispatch_root_queue_drain + 664
13 libdispatch.dylib 0x19534675c _dispatch_worker_thread3 + 108
14 libsystem_pthread.dylib 0x1955152e4 _pthread_wqthread + 816
15 libsystem_pthread.dylib 0x195514fa8 start_wqthread + 4
这是我的支票收据代码:
func checkReceipt(){
var appStoreURL = "https://buy.itunes.apple.com/verifyReceipt"
#if DEBUG
appStoreURL = "https://sandbox.itunes.apple.com/verifyReceipt"
#endif
var appStoreStatusZero = false // we connected to correct app store
if let url = NSBundle.mainBundle().appStoreReceiptURL {
if let receipt = NSData(contentsOfURL: url) {
var error: NSError?
let requestContents = ["receipt-data": receipt.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))]
let requestData = NSJSONSerialization.dataWithJSONObject(requestContents, options: NSJSONWritingOptions(rawValue: 0), error: &error)
if requestData == nil {
println("not receiving request Data")
}
let storeURL = NSURL(string: appStoreURL)
let storeRequest = NSMutableURLRequest(URL: storeURL!)
storeRequest.HTTPMethod = "POST"
storeRequest.HTTPBody = requestData
let queue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(storeRequest, queue: queue, completionHandler: {
response, data, error in
if error != nil {
println("connection error")
return
} else {
var error: NSError?
let jsonResponse = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions(rawValue: 0), error: &error) as NSDictionary?
if jsonResponse == nil {
println("json error")
return
} else {
var receiptInfo = jsonResponse?.objectForKey("receipt") as NSDictionary?
var inAppInfo = receiptInfo?.objectForKey("in_app") as NSArray?
var thisIAPInfo = inAppInfo?.objectAtIndex(0) as NSDictionary?
var removeAdsID = thisIAPInfo?.objectForKey("product_id") as String?
if removeAdsID == self.productID {
self.adsRemoved = true
}
}
}
})
}
}
}
我在这里做的有什么明显的错误吗?我不知道哪里错了。
有什么方法可以像在应用商店上一样进行测试吗?我尝试过临时部署,但我的应用程序运行良好。在无法测试的情况下很难判断我是否修复了错误!
首先,您永远不应该直接从设备上使用 Apple 服务器验证收据。这不是很安全。您应该选择本地收据验证,或者您的服务器收据验证,以防与苹果验证服务器通信。
我认为您的代码正在崩溃,因为您没有检查这些语句的结果。在某个地方你变得零和崩溃。
var receiptInfo = jsonResponse?.objectForKey("receipt") as NSDictionary?
var inAppInfo = receiptInfo?.objectForKey("in_app") as NSArray?
var thisIAPInfo = inAppInfo?.objectAtIndex(0) as NSDictionary?
var removeAdsID = thisIAPInfo?.objectForKey("product_id") as String?
尝试使用if let
结构。并在获取元素之前检查数组边界,它可能是空的。
类似的东西:
if let receiptInfo = jsonResponse.objectForKey("receipt") as NSDictionary? {
if let inAppInfo = receiptInfo.objectForKey("in_app") as NSArray? {
if (inAppInfo.count > 0) {
if let thisIAPInfo = inAppInfo.objectAtIndex(0) as? NSDictionary {
if let removeAdsID = thisIAPInfo.objectForKey("product_id") as String? {
// Do what you want here
}
}
}
}
}
要了解如何让它更漂亮,您可以阅读以下内容: http://blog.scottlogic.com/2014/12/08/swift-optional-pyramids-of-doom.html