在使用 Amazon iOS SDK 的 swift iOS 应用程序中,如何为 AWSS3TransferUtility 下载操作设置自定义超时?

Alf*_*uro 1 amazon-s3 ios swift

我在 iOS 12 的 swift 应用程序中使用适用于 iOS 的 AWS 开发工具包。我的应用程序必须列出 AWS S3 存储桶中的文件并下载其中的一些文件。列表文件操作运行良好,我成功地控制了其超时。我没有成功地完成下载任务。我的代码如下:

let credentialProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityPoolId: "<pool-id>")
let configuration = AWSServiceConfiguration(region: AWSRegionType.APSoutheast2, credentialsProvider: credentialProvider)

configuration?.timeoutIntervalForRequest = 30.0
configuration?.timeoutIntervalForResource = 86400


let transferUtilityConfiguration = AWSS3TransferUtilityConfiguration.init()

transferUtilityConfiguration.timeoutIntervalForResource = 86400
transferUtilityConfiguration.retryLimit = 1

AWSS3TransferUtility.register(with: configuration!, transferUtilityConfiguration: transferUtilityConfiguration, forKey: "com.mykey")

transferUtility = AWSS3TransferUtility.s3TransferUtility(forKey: "com.mykey")


let bucket = "com.mybucket"


transferUtility.configuration.maxRetryCount = 1

let urlForSavingFile = URL.init(fileURLWithPath: "")


transferUtility.download(to: urlForSavingFile, bucket: bucket, key: self.latestFileOnServer.key, expression: expression, completionHandler: self.completionHandler).continueWith { (task) -> AnyObject? in
            if let error = task.error {
                NSLog("Error: %@",error.localizedDescription);
                DispatchQueue.main.async(execute: {
                    statusLabel.text = "Failed"
                })
            }

            if let _ = task.result {

                self.refDownloadTask = task.result
                self.refDownloadTask?.setCompletionHandler(self.completionHandler!)
                methodStart = Date.init()

                let formatter = DateFormatter.init()

                formatter.dateFormat = "dd' 'MMM' 'YYYY' - 'HH:mm:ss"
                formatter.locale = Locale.init(identifier: "Europe / Rome")
                let italyDate = formatter.string(from: methodStart)

                print("Download started at \(italyDate)")
                DispatchQueue.main.async(execute: {
                    //statusLabel.text = "Downloading..."
                })
                NSLog("Download Starting!")
                // Do something with uploadTask.
            }
            return nil;
        }
Run Code Online (Sandbox Code Playgroud)

如果我等待文件完成下载,则会正确调用完成处理程序,但如果我使用网络链接调节器关闭网络,则传输将永远挂起,并且永远不会调用完成处理程序。任何帮助深表感谢。谢谢

Alf*_*uro 5

经过多次测试,我成功找到了解决方案,让SDK尊重超时。在我的测试过程中,最初,我对命名约定有点困惑:

timeoutIntervalForResource是传输可以花费的最长时间,无论成功/失败。这可以通过 AWS SDK 开箱即用。

timeoutIntervalForRequest是我们感兴趣的值。它是任务在网络丢失后等待额外数据的时间间隔。它的计时器是从最后一个收到的数据包开始安排的。正如您在问题和评论中所读到的那样,AWS SDK 似乎没有遵守这一点。

此命名约定与 Apple Cocoa USURLSession 类系列相同。在我的研究过程中,我发现了这个答案。看来,对于将其配置实例化为后台配置的 URLSession 来说,这种行为一直存在。这不是一个不当行为,它只是自 iOS 8 以来后台下载的新标准。

现在,解决方案。通过在 AWS SDK Objective-C 代码中进行调试(是的,他们提供了完整的代码),我找到了这个位置。如果您打开 AWSS3TransferUtility.m 文件,在第 400 行左右,您会发现在此方法中:

- (instancetype)initWithConfiguration:(AWSServiceConfiguration *)serviceConfiguration
     transferUtilityConfiguration:(AWSS3TransferUtilityConfiguration *)transferUtilityConfiguration
                       identifier:(NSString *)identifier
                completionHandler: (void (^)(NSError *_Nullable error)) completionHandler {}
Run Code Online (Sandbox Code Playgroud)

这些陈述:

//Create the NS URL session
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:_sessionIdentifier];
configuration.allowsCellularAccess = serviceConfiguration.allowsCellularAccess;
configuration.timeoutIntervalForResource = transferUtilityConfiguration.timeoutIntervalForResource;
Run Code Online (Sandbox Code Playgroud)

为了使其工作,请将第一条语句替换为:

NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
Run Code Online (Sandbox Code Playgroud)

现在,在您的代码中:

let credentialProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityPoolId: "<pool-id>")
let configuration = AWSServiceConfiguration(region: AWSRegionType.APSoutheast2, credentialsProvider: credentialProvider)

configuration?.timeoutIntervalForRequest = 30.0
configuration?.timeoutIntervalForResource = 86400
Run Code Online (Sandbox Code Playgroud)

网络丢失 30 秒后,SDK 将触发完成处理程序并显示 -1001 错误。

我只在 Transferutilitydownload 任务上进行了测试,但它也应该适用于上传。我知道这个解决方案不是防弹的,因为它没有考虑会话配置标识符,但我会努力解决它。此外,该解决方案意味着更改 AWS SDK 代码,但只更改一行代码。此更改只是使 AWSS3TransferUtility 创建标准 URLSessionConfigurations 而不是后台配置。这可能还有其他副作用需要考虑。