18

I have implemented NSURLSession for downloading fairly large files from our servers. Now as long as I'm working in foreground or background and go back to the app the transactions are working and getting finished.

But if I force-quit the app using the the multitasking screen and re-open the app again. the downloading process is not getting finished although as I understood from the docs, it should, here what the docs state:

If an iOS app is terminated by the system and relaunched, the app can use the same identifier to create a new configuration object and session and retrieve the status of transfers that were in progress at the time of termination. This behavior applies only for normal termination of the app by the system. If the user terminates the app from the multitasking screen, the system cancels all of the session’s background transfers. In addition, the system does not automatically relaunch apps that were force quit by the user. The user must explicitly relaunch the app before transfers can begin again.

Meaning if I relaunch the app the transaction before the force-quit should started again, or are they? Is there an additional operation I need to commit in order this to work?

UPDATE: I stumbled on this project: https://github.com/Heikowi/HWIFileDownload#force-quit

That states:

Force Quit

After the app has been killed by the user, downloads do not continue in the background. On iOS 7 (and later) resume data is passed back.

Meaning there is a way to receive resume data even if the application was killed by the user in the background. Only the project is written in Objective-C and I can't understand what are they doing to achieve this.

halfer
  • 19,824
  • 17
  • 99
  • 186
Emil Adz
  • 40,709
  • 36
  • 140
  • 187

3 Answers3

28

After a force-quit the:

 NSURLSessionTaskDelegate - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error

delegate method will be called when the app is restarted. If the download task can be resumed the error object will contain the resume data:

[error.userInfo objectForKey:NSURLSessionDownloadTaskResumeData].

Using this data you can resume the download process by creating a NSURLSessionDownloadTask with:

(NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData*)resumeData.

More info about that can be found in Life Cycle of a URL Session with Custom Delegates, step 13.

Emil Adz
  • 40,709
  • 36
  • 140
  • 187
Fabio Felici
  • 2,841
  • 15
  • 21
  • Actually it's not too late, Thanks for your answer. Could you please elaborate how should I use this received data in order to resume the download. Like you said I receive it on didCompleteWithError method. Should I immediately start another task using the downloadTaskWithResumeData from the didCompleteWithError method, or I need to save the resumeData NSData object in the UserDefaults and use it the next time the application runs? – Emil Adz Oct 07 '15 at 12:48
  • The didCompleteWithError will be called as soon as you restart the app not when you force quit. So you can just assign the data to a property and check if this data exist when you want to start the download. – Fabio Felici Oct 07 '15 at 14:13
  • from the debugging process I see that I reach this method before the application is actually killed and not when it started. – Emil Adz Oct 07 '15 at 14:16
  • Ok I tried now and actually with iOS 9 simulator the method get called when you restart but with iOS 8 it is called when you kill. Which version are you using? Probably with iOS 8 you will have to save the data somewhere (e.g UserDefaults) but don't know if it will work for a large file. – Fabio Felici Oct 07 '15 at 14:25
  • So basically what you are saying is that I have to check what version of OS the device runs and based on that perform the right operation? Currently I'm running iOS 8 (didn't updated to 9 yet). This raises up another problem. If I currently downloading 4 files of 15 megas and kill the app I will have about 4 fairly large resumeData objects that I need to save in UserDefaults which might be very problematic. – Emil Adz Oct 07 '15 at 14:39
  • I have no real iOS 9 device to test (I tried on simulator ) so it might works in the same way as iOS 8 (didCompleteWithError called at force quit). I will create a demo to try your concurrent saving scenario. – Fabio Felici Oct 07 '15 at 14:58
  • 3
    @GonjiDev how is this possible? When your app resumes, are we to reassociate sessions? On being terminated, `NSURLSession` loses reference to our delegate to be able to call it. Edit: Nevermind, quoting Apple here: `Create a session configuration. For background sessions, this configuration must contain a unique identifier. Store that identifier, and use it to reassociate with the session if your app crashes or is terminated or suspended.` (https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/URLLoadingSystem/NSURLSessionConcepts/NSURLSessionConcepts.html) – Angad Oct 06 '16 at 15:18
  • Thank you, this was the only clear instructions that i could find, and it works. – Cristi Băluță Mar 18 '19 at 10:03
1

I think that after your application did force-quit you should start all over again (.

If the user terminates your app, the system cancels any pending tasks.

and

When all of the tasks associated with a background session are complete, the system relaunches a terminated app (assuming that the sessionSendsLaunchEvents property was set to YES and that the user did not force quit the app)

https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html

Mike Demidov
  • 1,117
  • 11
  • 20
0

-> use URLSession background Sessions download doesn't stop at all....you don't have to explicitly code for resuming the download or something..

https://developer.apple.com/reference/foundation/urlsession

check for background session in this link...if you're not able get the still...comment me and i would help in detail.