我的应用程序仅在 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
                            }
                        }
                    }
                })


            }
        }

    }
  1. 我在这里做的有什么明显的错误吗?我不知道哪里错了。

  2. 有什么方法可以像在应用商店上一样进行测试吗?我尝试过临时部署,但我的应用程序运行良好。在无法测试的情况下很难判断我是否修复了错误!

首先,您永远不应该直接从设备上使用 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