Swift URLSession DataTask 在应用程序进入后台时失败

Posted

技术标签:

【中文标题】Swift URLSession DataTask 在应用程序进入后台时失败【英文标题】:Swift URLSession DataTask Fails when the app enters the background 【发布时间】:2019-06-26 20:59:19 【问题描述】:

根据Apple:

注意 您不必像本文中描述的那样使用后台会话执行所有后台网络活动。声明适当后台模式的应用可以使用默认 URL 会话和数据任务,就像它们在前台一样。

我正在尝试将我的 DataTask 与默认会话配置和委托(不是完成处理程序)一起使用,但如果我按下主页按钮并再次切换回应用程序,我的数据任务总是失败:

Task <A25361F9-CAC0-4FA8-8663-777E1C6878A2>.<2> load failed with error Error Domain=NSPOSIXErrorDomain Code=53 "Software caused connection abort" UserInfo=_NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <A25361F9-CAC0-4FA8-8663-777E1C6878A2>.<2>, _kCFStreamErrorDomainKey=1, NSErrorPeerAddressKey=<CFData 0x108f07b40 [0x1db6c1420]>length = 16, capacity = 16, bytes = 0x100201bb68118e240000000000000000, _kCFStreamErrorCodeKey=53, _NSURLErrorRelatedURLSessionTaskErrorKey=(
"LocalDataTask <A25361F9-CAC0-4FA8-8663-777E1C6878A2>.<2>"

我尝试了什么:使用共享会话,有或没有完成处理程序,同样的问题。

我的问题是:“声明适当后台模式的应用程序可以使用默认 URL 会话和数据任务”是什么意思?你如何声明这些背景模式?

我唯一遇到的是UIApplication.shared.beginBackgroundTask

这就是 Apple 所说的“适当的背景模式”吗?还是我错过了什么?

谢谢

【问题讨论】:

不,这是正确的方法。您可以使用beginBackgroundTask 获得最多 180 秒的时间来完成您的任务。 @Paulw11 我在文档中找不到 180 秒的数字,你确定它是正确的吗? 180 秒是适用于所有 ios 应用程序的后台时间,但该值可能会随 Apple 的突发奇想在不同版本之间发生变化(但多年来一直是 180 秒);您所知道的是,您提供的expirationHandler 将在您的应用程序用完之前不久被调用。如果您在调用过期处理程序时没有结束后台任务,那么 iOS 将终止您的应用程序。 您也可以使用backgroundTimeRemaining查看您的后台剩余时间;但是请注意,在 Xcode 后台运行时不会强制执行时间限制。 【参考方案1】:

是的,beginBackgroundTask(withName:expirationHandler:) 是请求操作系统给您的应用一点时间来完成它在用户离开应用之前启动的请求的正确方法。见Extending Your App's Background Execution Time。

这就是 Apple 所说的“适当的背景模式”吗?

他们谈论的是可能让您的应用在后台运行的任何技术。见About the Background Execution Sequence。 “后台任务”就是其中一种模式,即使您的应用不再处于前台,您也可以在有限的时间内完成任务。

另一个是background fetch。如果启用,在后台获取期间,操作系统可以自行决定在后台启动您的应用程序,让您执行请求,然后在完成后调用完成处理程序。 (在这种情况下,您的时间甚至不到 3 分钟,更像是 30 秒 IIRC。)这是“适当的背景模式”的一个示例,您将使用标准/默认 URLSessionConfiguration,而不是背景模式. Apple 指出了这一点,因为否则很容易假设任何与背景相关的网络请求都需要背景URLSessionConfiguration。但事实并非如此。

因此,如果您只是想让应用程序继续运行一点以完成任务,即使用户点击了主页按钮,那么 beginBackgroundTask 与标准 URLSession 结合使用就足够了。或者,如果您碰巧使用了其中一种“已批准的后台模式”(这听起来不像您的情况),那么标准的 URLSession 就足够了。

后台URLSession 确实适用于请求可能需要比分配时间更长的情况。也许您正在下载许多非常大的资产,例如电影,这可能需要几分钟以上的时间。只有在这种情况下,您才需要使用背景URLSessionConfiguration.background(withIdentifier:)。这仅取决于请求需要多长时间。

【讨论】:

以上是关于Swift URLSession DataTask 在应用程序进入后台时失败的主要内容,如果未能解决你的问题,请参考以下文章

重试 URLSession dataTask 的模式?

如何同步 URLSession 任务的串行队列?

URLSession.shared.dataTask vs dataTaskPublisher,啥时候用哪个?

有没有办法使用 URLSession.shared.dataTask 并行请求多个不同的资源

在 URLSession.shared.dataTask 期间存储来自异步闭包的数据

使用完成处理程序进行异步调用的多个 URLSession dataTask 导致内存上升