ios 常驻后台上传
What’s the general thought that comes to any iOS Developer’s mind when they think of background tasks?
任何iOS开发人员想到后台任务时会想到什么?
That’s right, you would immediately think of the above API in UIApplication to extend the time of your app to run on background in order to complete your uploads/downloads. But what if the download/upload size if huge, let’s say for 500MB for example, and you are on LTE/3G connection. Would this still work? The answer is that there is no guarantee that your upload/download would complete, it is highly probable that your app might be killed by the system due to various reasons(like memory pressure, battery etc.) in between.
没错,您会立即想到上述UIApplication中的API,以延长应用程序在后台运行的时间,从而完成上载/下载。 但是,如果下载/上传大小很大(例如,假设为500MB),而您正在LTE / 3G连接上,该怎么办? 这仍然有效吗? 答案是,不能保证您的上传/下载会完成,这很可能是由于介于两者之间的各种原因(例如内存压力,电池电量等)导致您的应用被系统杀死。
How do we guarantee that this works? Does iOS have a solution for the same?
我们如何保证这有效? iOS是否有相同的解决方案?
Photo by Jake Young on Unsplash 杰克·杨( Jake Young)在 Unsplash上 摄The answer is YES, NSURLSessionConfiguration provides APIs to help with uploads/download working smoothly when backgrounding the app. The uploads/downloads using this API will work even if your app is killed by the OS. They won’t work if you force kill the app. iOS basically passes the upload/download task to the system’s upload daemon thread if your app is killed and for this very reason, its important to save your file to a permanent location on device.
答案是肯定的,NSURLSessionConfiguration提供API来帮助在使应用程序后台运行时顺利进行上载/下载。 即使您的应用被操作系统杀死,使用此API进行的上传/下载也将起作用。 如果您强行杀死应用程序,它们将无法工作。 如果您的应用程序被终止,iOS基本上会将上载/下载任务传递给系统的上载守护程序线程,因此,将文件保存到设备上的永久位置非常重要。
NSURLSessionConfiguration *backgroundConfig = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier]; //Determines the maximum number of simulataneous connections to a Host. This is a per session property. backgroundConfig.HTTPMaximumConnectionsPerHost = 1; // This controles whether you are allowed to continue your upload/download over cellular access. backgroundConfig.allowsCellularAccess = YES; // This makes sure you get an event on your app session launch (in your AppDelegate). (Your app might be killed by system even if your upload/download is going on) backgroundConfig.sessionSendsLaunchEvents = YES; // This tells the system to wait for connectivity and then resume uploading/downloading. If the network goes away, it will restart from 0. backgroundConfig.waitsForConnectivity = YES; // This just makes a new url session using the background configuration. NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:backgroundConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]];In the above code snippet, we need to make sure the identifier passed to the background session configuration is a unique identifier.
在上面的代码片段中,我们需要确保传递给后台会话配置的标识符是唯一的标识符。
Q: Now, how do we get the status of a running upload/download?
问:现在,我们如何获取正在运行的上传/下载的状态?
A: You can add the following API in your AppDelegate, which provides you with an identifier for a particular NSURLSession. OS usually wakes up your app with the once all the tasks in your session are complete and calls the following the API to let you know about the session progress.
答:您可以在AppDelegate中添加以下API,该API为您提供特定NSURLSession的标识符。 会话中的所有任务完成后,操作系统通常会唤醒您的应用程序,并调用以下API来告知会话进度。
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler { //Identifier here reperesent a URL Session whose tasks just finished and the OS woke up the app. }You can use the above method to reconnect your NSURLSessions and get the progress of your uploads/downloads. You need to make sure that the identifier you pass here is actually the identifier you are looking to get the progress for, otherwise things might not work as expected.
您可以使用上述方法重新连接您的NSURLSession,并获取上载/下载进度。 您需要确保在此处传递的标识符实际上是您要获取进度的标识符,否则可能无法按预期进行。
Q: How do I create a task for NSURLSession with background configuration?
问:如何使用后台配置为NSURLSession创建任务?
A: We can simply use a NSURLSessionUploadTask/NSURLSessionDownloadTask to upload/download a file along with the background configuration created above.
答:我们可以简单地使用NSURLSessionUploadTask / NSURLSessionDownloadTask来上传/下载文件,以及上面创建的后台配置。
// The background config here is from the code snippet above NSURLSession *urlSession = [NSURLSession sessionWithConfiguration:backgroundConfig delegate:self delegateQueue:[NSOperationQueue mainQueue]]; // Pass the urlRequest to your server // Pass the localfilepath to your file that you are trying to download/upload // Use NSURLSessionDownloadTask for downloading a file NSURLSessionUploadTask *uploadTask = [urlSession uploadTaskWithRequest:urlRequest fromFile:[NSURL fileURLWithPath:localFilePath]];What are the major problems faced using this pipeline?
使用此管道面临的主要问题是什么?
You need to save any file that you want to download/upload onto the disk. This generally also increases the IO operations during the time of upload/download, you will see a significant increase in CPU usage while the upload/download is going on. 您需要将要下载/上传的所有文件保存到磁盘上。 通常,这还会增加上载/下载期间的IO操作,在上载/下载进行期间,您会发现CPU使用率显着增加。 Custom protocols are not supported. 不支持自定义协议。Debugging this pipeline is very tough. The only way to see if your downloads/uploads are still running is to check logs on mac console or system diagnosis logs. Check section below.
调试此管道非常困难。 查看下载/上传是否仍在运行的唯一方法是检查Mac控制台上的日志或系统诊断日志。 检查下面的部分。
Its tough to mimic the scenario where OS force kills the app and you still want to check if your downloads/uploads are working. On phones below iPhoneX, you can replicate this by holding the power button until you see the switch off screen and then holding the home button. I am not sure if there is a way to do this in iPhoneX and above. Would be great if someone out there knows :) 很难模拟OS强行杀死应用程序,而您仍然要检查下载/上传是否正常的情况。 在iPhoneX以下的手机上,您可以通过按住电源按钮直到看到“关闭”屏幕,然后按住主屏幕按钮来复制此内容。 我不确定在iPhoneX及更高版本中是否有办法做到这一点。 如果外面有人知道:)You can’t keep on keep creating unlimited sessions. If your app is not active and is killed by OS, OS would wake up the app after every session finishes the tasks and iOS Resume Rate Limiter comes into picture. Every time a session wakes up the app, the wake up time increases every time and would keep on increasing and might result into your app not waking up at all. The best optimal strategy to avoid this is to just have one session and just keep on adding tasks to the same session. (Note: the above situation only occurs for uploads and not downloads.)
您不能继续创建无限的会话。 如果您的应用程序处于非活动状态并被OS杀死,则OS将在每个会话完成任务并且iOS Resume Rate Limiter出现后唤醒应用程序。 每次会话唤醒应用程序时,唤醒时间每次都会增加,并且会持续增加,并且可能导致您的应用程序根本无法唤醒。 避免这种情况的最佳最佳策略是只进行一个会话,然后继续将任务添加到同一会话中。 (注意:以上情况仅发生在上载而不发生在下载中。)
Testing in all conditions like wifi, slow wifi, LTE, 3G, no network, resuming uploads etc. takes a huge chunk of QA time. 在wifi,慢速wifi,LTE,3G,无网络,恢复上传等所有条件下进行测试都需要花费大量的质量检查时间。Debugging Screenshots from Mac console when the app is force killed by OS and the uploads are still continuing
当应用被操作系统强行杀死并且上传仍在继续时,从Mac控制台调试屏幕截图
This is how the logs would look like when a background configuration session is initialized and the uploads are about to start.
这是初始化后台配置会话并且即将开始上载时日志的外观。
Background upload starting logs 后台上传启动日志And this is how the logs would look like when you have backgrounded the app, and OS has killed your app, but the uploads are still going on. The OS will try to wake up your app and send you a app delegate event as soon as all the tasks of a session are finished.
这就是您为应用程序添加背景并且OS终止了您的应用程序后日志的外观,但是上传仍在继续。 会话的所有任务完成后,操作系统将尝试唤醒您的应用并向您发送应用委托事件。
Background upload end logs 后台上传结束日志Takeaways from our implementation at Fyusion Inc
在Fyusion Inc实施中的要点
We moved to a single file upload just to make sure its easier to maintain status of an ongoing upload and everything can be done with just one task in a NSURLSession. Highly recommend doing it this way if you have a queueing architecture in your pipeline. Just keep on adding tasks to a single NSURLSession. We learnt this hard way that it was not wise to create multiple NSURLSession’s for this pipeline. 我们移至单个文件上载只是为了确保其易于维护正在进行的上载状态,并且只需使用NSURLSession中的一项任务就可以完成所有操作。 如果您的管道中有排队体系结构,强烈建议采用这种方式。 只需继续将任务添加到单个NSURLSession中即可。 我们以这种艰难的方式学习到,为此管道创建多个NSURLSession是不明智的。Moving to one NSURLSession also takes care of iOS Resume Rate Limiter. (Note: Having a single file also has its own problems, like how would you handle very large size of files. We are still working on it and would probably go ahead with sharding of files with huge file sizes.)
移至一个NSURLSession还可以处理iOS Resume Rate Limiter 。 (注意:拥有一个文件也有其自身的问题,例如您将如何处理非常大的文件。我们仍在努力之中,可能会继续对具有大文件大小的文件进行分片。)
Bombarding your app with multiple NSURLSessions might also lead to crashing of the upload daemon thread of your OS and in result crashing the whole device. (But for this the number of sessions need to be crazy high, not a usual scenario :) ) 使用多个NSURLSession轰炸您的应用程序还可能导致操作系统的上载守护程序线程崩溃,并导致整个设备崩溃。 (但是为此,会话数需要非常高,这不是通常的情况:)) Maintaining internal states of background uploads progress is very important especially if you are developing a SDK. The clients need to have access of what state the upload is in even after resuming an app. 维护后台上传进度的内部状态非常重要,尤其是在开发SDK时。 即使恢复了应用程序,客户端也需要访问上载的状态。 Resumable downloads is always an option, but resumable uploads is not an option. The only option for optimizing uploads is to create chunks of your file. 断点续传始终是一种选择,而断点续传不是一种选择。 优化上传的唯一选择是创建文件块。Important Resources
重要资源
https://developer.apple.com/forums/thread/10239
https://developer.apple.com/forums/thread/10239
https://developer.apple.com/documentation/foundation/url_loading_system/downloading_files_in_the_background
https://developer.apple.com/documentation/foundation/url_loading_system/downloading_files_in_the_background
翻译自: https://medium.com/swlh/demystifying-background-uploads-downloads-in-ios-53f5ba465f0b
ios 常驻后台上传
相关资源:微信小程序源码-合集6.rar