Has anyone got any tips on how to reconnect to a download in a NSURLSession after a crash.
If my app crashes, I believe the download continues on the device anyway, and then when my app relaunches I can use the same sessionID in:
NSURLSessionConfiguration.backgroundSessionConfiguration(sessionID)
However, am I then supposed to call 'session.getTasksWithCompletionHandler' to see if there are any tasks? The docs aren't clear.
My UI has a download progress bar for each file download, so ideally when I relaunch the app, it would try and reconnect and hook the progress back up to the UI.
At the moment what is happening is I restart the download, and my progress bar flickers because there are 2 downloads in progress - the old one and a new one, and then it gets itself into a state...
Ok here is what I found, in the URL System Programming Guide:
In both iOS and OS X, when the user relaunches your app, your app
should immediately create background configuration objects with the
same identifiers as any sessions that had outstanding tasks when your
app was last running, then create a session for each of those
configuration objects. These new sessions are similarly automatically
reassociated with ongoing background activity.
So once I create the session again and hook up the delegate, the delegate methods start firing again, and I use getTasksWithCompletionHandler to see if there were any tasks in progress and return this to my UI and the rest of the system
Related
I figured out about it is possible to download in background mode of application. I have implemented Background Fetching Mode in XCode and registered background task and its working fine.
Is it possible to resume downloading task after force closing my application by user? How?
No, you can't continue download when your app get terminated by user! Your app must require to remains in background state!!! Because if user force close app that means, he doesn't want to run it anymore. If your app is suspended by system then it can be wake up but not if it's terminated by user!
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.
Update : (As asked in comment)
Refer the apple documentation, It states,
This method lets your app know that it is about to be terminated and purged from memory entirely. You should use this method to perform any final clean-up tasks for your app, such as freeing shared resources, saving user data, and invalidating timers. Your implementation of this method has approximately five seconds to perform any tasks and return. If the method does not return before time expires, the system may kill the process altogether.
For apps that do not support background execution or are linked
against iOS 3.x or earlier, this method is always called when the user
quits the app. For apps that support background execution, this method
is generally not called when the user quits the app because the app
simply moves to the background in that case. However, this method may
be called in situations where the app is running in the background
(not suspended) and the system needs to terminate it for some reason.
After calling this method, the app also posts a
UIApplicationWillTerminate notification to give interested objects a
chance to respond to the transition.
When any task completes, the NSURLSession object calls the delegate’s URLSession:task:didCompleteWithError: method with either an error object or nil (if the task completed successfully).
If the task failed, most apps should retry the request until either the user cancels the download or the server returns an error indicating that the request will never succeed. Your app should not retry immediately, however. Instead, it should use reachability APIs to determine whether the server is reachable, and should make a new request only when it receives a notification that reachability has changed.
If the download task can be resumed, the NSError object’s userInfo dictionary contains a value for the NSURLSessionDownloadTaskResumeData key. Your app should pass this value to call downloadTaskWithResumeData: or downloadTaskWithResumeData:completionHandler: to create a new download task that continues the existing download.
If the task cannot be resumed, your app should create a new download task and restart the transaction from the beginning.
checkout here: Life cycle of URL Session
Yes—if I understood your need right—Apple allows this with State Preservation and Restoration APIs:
Return your app to its previous state after it is terminated by the system.
Check Apple's article: Preserving Your App's UI Across Launches, for an overview of this framework.
Details about preservation process can be found in article: About the UI Preservation Process
Details about restoration process can be found here: About the UI Restoration Process
Raywenderlich have—a little outdated—tutorial implementation of this framework # State Restoration Tutorial: Getting Started
I was trying to open a URL session for a chunked response, I am able to achieve this by setting backgroundSessionConfigurationWithIdentifier in NSURLSessionConfiguration object. The URL session still runs if app goes to background, but the session terminates once I quit the app by swapping out from multitask view. Is there a way to restrict quitting the app till didFinishDownloadingToURL delegate called.
I have achieved the similar functionality in my android app using a native thread (boost thread reside in a .so called by UI thru JNI) which does not terminate if the UI is swapped out from the multi task view. Is there a way to achieve same in IOS app?
regards,
Birajendu
According to NSURLSession guide background session task executes in different process (not thread). And finished even if initiator app was killed. You can reassign to bg task when relaunch app.
In both iOS and OS X, when the user relaunches your app, your app should immediately create background configuration objects with the same identifiers as any sessions that had outstanding tasks when your app was last running, then create a session for each of those configuration objects. These new sessions are similarly automatically reassociated with ongoing background activity.
Not sure is it possible to get the task result if your app was terminate during bg session and session completed before you restart app.
I am trying to understand Apple's doc for Background Execution:
Once configured, your NSURLSession object seamlessly hands off upload
and download tasks to the system at appropriate times. If tasks finish
while your app is still running (either in the foreground or the
background), the session object notifies its delegate in the usual
way. If tasks have not yet finished and the system terminates your
app, the system automatically continues managing the tasks in the
background. If the user terminates your app, the system cancels any
pending tasks.
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) and calls the app delegate’s
application:handleEventsForBackgroundURLSession:completionHandler:
method. (The system may also relaunch the app to handle authentication
challenges or other task-related events that require your app’s
attention.) In your implementation of that delegate method, use the
provided identifier to create a new NSURLSessionConfiguration and
NSURLSession object with the same configuration as before. The system
reconnects your new session object to the previous tasks and reports
their status to the session object’s delegate.
If I use NSURLSession, so when app goes background when uploading process is still on going, the process won't be killed or died as long as the application isn't terminated by user (I assume this is by killing my app from app list) ?
Read the text carefully. As all good documentation, it says very clearly what it means, and you just need to read it carefully.
You didn't read it carefully.
There are three cases: Your app is still running when a task finishes, your app has been shut down by the system when the last task finishes, or the user has closed down the app before the last task finishes. No, it doesn't say anywhere that the app is kept alive. And the documentation says clearly what happens in each case.
iOS kills apps that are in the background and makes it look to the user as if they are still running.
I'm little bit confused with background fetch. I read in Apple Developer documentation that fetch happens when OS decides that it should, user can't control background fetch, while on Apple Developer forum post by Apple employee says that if user kills app (double tap on home and button swipe up) background fetch wont happen, in that case user can control background fetch. So can someone please clarify to me if user kills the app with task manager will background fetch still continue in the background or it's killed at the same time as app.
Apple documentation:
https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1
From the doc you link:
When a good opportunity arises, the system wakes or launches your app into the background and calls the app delegate’s application:performFetchWithCompletionHandler: method.
So, it seems that the system is able to launch in the background an app that is not running so it executes a background fetch. On the other hand, though, later in the document you can read:
In most cases, the system does not relaunch apps after they are force quit by the user. One exception is location apps, which in iOS 8 and later are relaunched after being force quit by the user. In other cases, though, the user must launch the app explicitly or reboot the device before the app can be launched automatically into the background by the system.
So, Apple's engineer is right: force quitting an app puts it into a sort of special case where background fetches are not allowed anymore.
If the user feels the need to allow background operations, he wouldn't kill the app. But when he kills it, it is only appropriate to disallow background fetch. User can only control if background fetch should happen or not by allowing it to stay in background/by killing the app. But once the app is in background, user cannot control "when" the background fetch happens. The OS determines it based on how free it is.
I think this quote (from the linked document) is the most important for the scenario you're describing:
Once configured, your NSURLSession object seamlessly hands off upload and download tasks to the system at appropriate times. If tasks finish while your app is still running (either in the foreground or the background), the session object notifies its delegate in the usual way. If tasks have not yet finished and the system terminates your app, the system automatically continues managing the tasks in the background. If the user terminates your app, the system cancels any pending tasks.
I have implemented sample tutorial for background transfer service given in below link also edited the name of the scheme and selected the check box for "Background Fetch ... Launch due to a background fetch event"
http://www.techotopia.com/index.php/An_iOS_7_Background_Transfer_Service_Tutorial
This sample works fine.It downloads image before app starts.
If next time when app is restarted and kept in background it downloads image as well.
Now If I remove the app from multitasking card view then app does not download the image when start app again.
I have read below description in apple doc
(NSURLSessionConfiguration *)backgroundSessionConfiguration:(NSString *)identifier
Parameters
identifier
An identifier for the new session configuration that is unique for your app. Your app can retrieve the download or the upload response later by creating a new background session with the same identifier.
Discussion
Sessions created with configuration objects returned by this method are called background sessions. These sessions differ from other sessions in the following ways:
Upload and download tasks in background sessions are performed by an external daemon instead of by the app itself. As a result, the transfers continue in the background even if the app is suspended, exits, or crashes.
Need to know how do I check the transfers continue in the background even if the app is suspended, exits, or crashes??
Add exit(0); to your code immediately after the download starts. Then see if it still continues downloading or not.