I use URLSessions to do my network calls and it always fails when I put my app to background state.
When I bring the app to foreground state, the URLSession give URLResponse as nil.
How can I make it work in background state?
You can get URLSession to work in background state if you configure session for background download or upload. But if you use session for regular backend API call, best that you can do is to repeat call after application enter foreground again.
Related
I am working on an iOS application where the app is supposed to make a server request before going to background mode. I app should not wait for the response as that's not needed. The sole purpose of this request is that I need to keep the status of the app in my DB to know if the user is online/offline.
As the app goes to background, i make the server request and put the app into sleep mode by sleep(3) so that it can successfully finish the server call.
func applicationDidEnterBackground(_ application: UIApplication) {
//make a server call
sleep(3) //so that app can submit request to server before closing
}
This works fine but if I open the app again (comes to foreground) before that sleep time has been finished, the app does not respond to any kind of user inputs/taps. Even the applicationDidBecomeActive method does not get called. It waits for that sleep time to finish that I had set before.
How can I cancel the sleep mode when the app becomes active?
Don't use sleep. Instead, make your server request using a URLSession that is suitable for background processing:
let session = URLSession(configuration: .background(withIdentifier: "foo"))
I have been using NSURLSession to do background uploading to AWS S3. Something like this:
NSURLSessionConfiguration* configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#“some.identifier"];
NSURLSession* session = [NSURLSession sessionWithConfiguration:configuration delegate:someDelegate delegateQueue:[NSOperationQueue mainQueue]];
NSURLSessionUploadTask* task = [session uploadTaskWithRequest:request fromFile:[NSURL fileURLWithPath:httpBody]];
[task resume];
In someDelegate, I have implemented didSendBodyData, didCompleteWithError and handleEventsForBackgroundURLSession.
I have three questions:
I have noticed that if I close the app while uploading is in progress, transfer will continue and successfully finish. Is handleEventsForBackgroundURLSession called when the transfer is finished while the app is closed?
Assuming that the answer to the first question is yes, how can I delete httpBody in handleEventsForBackgroundURLSession? This is a temporary file that is not needed once transfer is complete.
I would appreciate it if someone explained, in detail, how background transfer works in iOS. That is when memory is created, which callbacks are called at which states and how the app is woken up once the transfer is completed. Thanks.
When the app delegate's handleEventsForBackgroundURLSession is called, you should:
save the completion handler;
instantiate your background NSURLSession;
let all of your delegate methods to be called;
in your URLSession:task:didCompleteWithError:, you can remove those temp files; and
in URLSessionDidFinishEventsForBackgroundURLSession:, you can call that saved completion handler.
A few additional notes:
There seems to be some confusion about what happens when an app is terminated.
If the app is terminated in the course of its normal lifecycle, the URLSession daemon will keep the background requests going, finishing your uploads, and then wake up your app when it's done.
But manually force-quitting the app (e.g., double tapping on home button, swiping up on the app to force it to quit) is a completely different thing (effectively, the user is saying "stop this app and everything associated with it"). That will stop background sessions. So, yes, background sessions will continue after the app is terminated, but, no, not if the user force-quit the app.
You talk about setting breakpoints and observing this in Xcode. You should be aware that the process of being attached to Xcode will interfere with the normal app life cycle (it keeps it running in background, preventing it from being suspended or, during the normal course of events, terminating).
But when testing background session related code, it's critical to be test the handleEventsForBackgroundURLSession workflow when your app was terminated, so to that end, I'd suggest not using Xcode debugger when testing this dimension of background sessions.
I use the new OSLog unified logging system, because the macOS Console can watch what is logged by the app, while not having Xcode running at all. Then I can write code that starts some download or upload, terminates app and then watch the logging statements I have inserted in order to observe the restarting of the app in background via the macOS console. See Unified Logging and Activity Tracing video for a tutorial of how to watch iOS logs from the macOS Console.
I have develop a HTTP module for making upload download request using URLSession Background sessions.
The HTTP module work in Serialize mode as specified in URLSession doc by passing nil to queue.
On download complete urlSession(_:downloadTask:didFinishDownloadingTo:) i do parsing.Based on parsing make request for other file from the same module.
Everything works OK in foreground.
But as i move the application to background by pressing home button downloading and parsing stops.
Because of which i can't able to make another file request in background.
And if application move to foreground downloading will resume.
Can any one help me out for this ?
I have a prototype single-view app which monitors download tasks.
I'm trying to deal with following use case:
Downloads are initiated via NSURLSession while app is in foreground. NSURLSession is created with background configuration.
I kill the app with "Xcode Stop", so that app continues download in background. While app is alive, I orderly receive progress callbacks from NSURLSession.
I manually start the app (not by Xcode, but tapping the launch icon), when the downloads have not been completed yet.
I don't receive any URLSession delegate calls for tasks started in previous app's life. The only thing that gets called is handleEventsForBackgroundURLSession but that's called on AppDelegate by the OS (different case than NSURLSession delegate calls).
I want to show progress of ongoing download tasks. Can this be done after app relaunch (when app was terminated by the system, not manually!)?
After app relaunch, NSURLSession is initialized with same identifier, new delegate object, so I figured delegate will continue to receive calls for session's tasks (because session identifier is the same), but apparentely that's not the case.
There is a note in Apple's documentation:
The session object keeps a strong reference to the delegate until your app explicitly invalidates the session. If you do not invalidate the session, your app leaks memory.
but I guess this only applies to case when app is alive. When the app is terminated, then all app's objects are gone.
Make sure NSURLSession is properly initialised when app launches. That's what the problem was in my case. I had TransferManager which initialised session as lazy getter which was not getting invoked...
Now that the NSURLSession is properly initialised, callbacks are fired regularly.
Stupid error, but there it is.
You goal seems to be in number 4, trying to receive URLSession delegate callbacks while in the background. I've been struggling with that myself and wasn't able to find a great solution, however I did realize that whenever I performed any actions (even simply calling the completionHandler() callback) in handleEventsForBackgroundURLSession: I received a call to
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
Seems like performing operations might wake up the delegate that was specified when creating your NSURLSession.
That is the correct method to perform any UI updates (such as showing progress) since that's the only location you'll know the background task is complete. Just make sure to call the completion handler callback after you are done!
Also this may be of some help to you: My NSURLSessionDelegate methods are not getting called during a background download
I want to upload a file to a server using NSURLSession.
Cases Are:
1. It should resume uploading a file to the server from where it stopped because of app crash.
2. It should handle background upload as well.
Try AFNetworking Library to upload image asynchronously.You can find a brief example in this thread.
You should use background NSURLSession. If your app crashed or user left the app while upload was in progress, with a background NSURLSession the upload would continue seamlessly in the background. When the upload is done, your app will be notified of this via the delegate (and if your app wasn't alive at the time the download finished, it will be started in a background mode, at which point you can do whatever cleanup you need).
So create NSURLSessionConfiguration with backgroundSessionConfigurationWithIdentifier, and then instantiate a NSURLSession with that configuration.
There are a few caveats:
You cannot use completion handler pattern. You have to use delegate-based implementation.
You have to implement handleEventsForBackgroundURLSession in the app delegate, capturing the completionHandler it passes you and also instantiate the background session again. Likewise, in your NSURLSession delegate methods, you have to implement URLSessionDidFinishEventsForBackgroundURLSession, which will call the saved completion handler.
For more information, see Background Task Considerations in URL Session Programming Guide, see a section of the same name (but different text) in the NSURLSession class reference, or see the WWDC 2013 What's New in Foundation Networking, where Apple first introduced us to background sessions.