离线时在 iOS 上进行 http 调用
Posted
技术标签:
【中文标题】离线时在 iOS 上进行 http 调用【英文标题】:Make http call on iOS while offline 【发布时间】:2014-08-16 20:51:59 【问题描述】:也许我一直在阅读错误的内容,但我一直在阅读的所有文献似乎都同意一件事:ios 不允许后台线程运行超过十分钟。这似乎违反了应用程序开发的最大原则之一:您的用户应该看不到互联网。所以这是一个场景。
用户正在通过隧道或在飞机上飞行,导致网络不可靠或不可靠。在那一刻,用户打开了我的电子邮件应用程序,撰写了一封电子邮件,然后点击了发送按钮。
问题:开发人员如何确保在网络可用时发送电子邮件?当然,我使用电子邮件作为一般示例,但实际上我正在处理一个非常简单的 http 情况,我的应用程序需要向我的服务器发送 POST。
旁注:在 android 上,我使用 Path 的优先作业队列,它允许我设置它并忘记它(即只要有网络它就会发送我的电子邮件)。
另一个旁注:我一直在尝试将 NSOperationQueue 与 AFNetworking 一起使用,但没有这样做。
【问题讨论】:
【参考方案1】:您想要实现的目标可以使用背景NSURLSession
来完成。虽然 AFNetworking 是基于 NSURLSession 我不太确定它是否可以与后台会话一起使用而你的应用程序没有。但是你真的不需要这个,NSURLSession 很容易使用。
作为第一步,您需要为后台会话创建会话配置:
let config = URLSessionConfiguration.background(withIdentifier: "de.5sw.test")
config.isDiscretionary = true
config.waitsForConnectivity = true
isDiscretionary
属性允许系统决定何时执行数据传输。 waitsForConnectivity
(自 iOS 11 起可用)在没有互联网连接时让系统等待,而不是立即失败。
使用该配置对象,您可以创建 URL 会话。重要的部分是指定一个委托,因为当应用终止时,基于闭包的回调会丢失。
let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
要执行上传,您要求会话创建一个上传任务,然后恢复它。对于上传任务,您首先创建您的URLRequest
,指定 URL 和所有需要的标头。您要上传的实际数据需要写入文件。如果您将其作为Data
或流对象提供,则在您的应用终止后将无法上传。
let task = session.uploadTask(with: request, fromFile: fileUrl)
task.resume()
要获得上传成功或失败的通知,您需要实现URLSessionDataDelegate
方法urlSession(_:task:didCompleteWithError:)
。如果错误为nil
,则传输成功。
最后缺少的部分是处理在您的应用未运行时发生的事件。为此,您在应用程序委托中实现方法application(_:handleEventsForBackgroundURLSession:completionHandler:)
。当系统决定您需要处理一些后台传输事件时,它会在后台启动您的应用并调用此方法。
您需要首先存储完成处理程序,然后使用您之前使用的相同配置重新创建您的 URLSession。然后,这将它称为您需要照常处理的事件的委托。一旦完成事件,它就会调用委托方法urlSessionDidFinishEvents(forBackgroundURLSession:)
。从那里您需要调用传递给您的应用委托的完成处理程序。
会话配置提供了更多选项:
timeoutIntervalForResource
: 系统应该尝试多长时间执行您的上传。默认为 7 天。
sessionSendsLaunchEvents
:如果false
将不会启动应用程序来处理事件。当用户手动打开应用程序时,它们将被处理。默认为true
。
这是一个小示例项目,展示了所有内容如何组合在一起:https://github.com/5sw/BackgroundUploadDemo
【讨论】:
【参考方案2】:您的应用需要在内部存储数据,然后您需要一些可以使应用在后台运行的东西(但如果您还没有理由这样做,则不必特别添加一些东西) 或等到用户下一次将应用程序带到前台 - 然后您可以检查网络连接并拨打电话。
请注意,电子邮件与 POST 非常不同,因为您可以将电子邮件传递给系统邮件应用程序为您发送,但您不能对 POST 执行完全相同的操作。
如果可以使用,请考虑查看NSURLSessionUploadTask
。
【讨论】:
【参考方案3】:三个字:你不知道。
这实际上是一件好事。 我当然不想思考和推测我最近的 20 个应用程序,如果它们仍在后台运行,使用内存、电池和带宽。此外,如果需要更多内存,它们将被杀死。用户如何能够预测它是否成功完成了任务?他不能,需要无论如何打开应用程序检查。
至于电子邮件示例,我会将电子邮件显示为“待处理”(即未发送),直到它正确传输。让用户明白他必须稍后再回来完成工作。
虽然每个开发人员都认为他的应用程序有非常好的理由进行后台处理,但现实情况是,对于 99% 的用户来说,这只是一种痛苦。你能说“任务管理器”吗? ;-)
【讨论】:
您的应用无需运行即可在后台上传数据。这就是背景 NSURLSession 的用途。它使系统可以选择何时是上传的最佳时间。当然,您关于在 UI 中显示挂起状态的观点很好。但是您不必让用户在上传过程中等待并观看应用程序。 是的,在 3 1/2 年内情况发生了一些变化。【参考方案4】:我写了一个几乎可以做到这一点的 pod - https://cocoapods.org/pods/OfflineRequestManager。如果您想监控请求是处于挂起状态还是已完成/失败状态,您必须做一些工作来监听委托回调,但我们一直在使用它来确保请求在连接不良或没有连接的情况下发出。
最简单的用例如下所示,但大多数实际用例(保存到磁盘、特定请求数据等)将有更多的障碍需要跳过:
import OfflineRequestManager
class SimpleRequest: OfflineRequest
func perform(completion: @escaping (Error?) -> Void)
doMyNetworkRequest(withCompletion: response, error in
handleResponse(response)
completion(error)
)
///////
OfflineRequestManager.defaultManager(queueRequest: SimpleRequest())
【讨论】:
以上是关于离线时在 iOS 上进行 http 调用的主要内容,如果未能解决你的问题,请参考以下文章
离线时在 Progressive Web App 中处理获取请求