2

This is the scenario:

  • NSURLSession with background Configuration
  • Download or upload task start with Bad or No Internet Connection.
  • User close the App.
  • If iOS get Internet Connection will star session task. However,
  • With task still waiting for Internet.
  • User kills the App
  • System cancel all pending tasks

The Question

It is possible to know when the user opens the app again that the tasks were cancelled?

If yes, where?


This Answer says yes, it is possible, but I can not get any callback returning me an error.

I'm using Alamofire to handle all my Networking calls. However, I doubt that Alamofire will change the behavior.


Edit 1

/// Networking manager with Background Session Configuration
static var backgroundManager: Alamofire.Manager = {

    let configuration = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier("com.xxx.NetworkingManager.Identifier")
    configuration.HTTPAdditionalHeaders = Manager.defaultHTTPHeaders

    let backgroundManager = Alamofire.Manager(configuration: configuration)
return backgroundManager
}()
Community
  • 1
  • 1
Gabriel.Massana
  • 8,165
  • 6
  • 62
  • 81
  • 1
    When the app restarts, are you definitely restarting the background `NSURLSession` with the appropriate identifier? Obviously you cannot rely upon [`handleEventsForBackgroundURLSession`](https://developer.apple.com/reference/uikit/uiapplicationdelegate/1622941-application) to start it, so you have to start it yourself. – Rob Nov 15 '16 at 15:41
  • I guess so. I updated the answer with my code to init the background NSURLSession. Do I need to so something there? – Gabriel.Massana Nov 15 '16 at 15:47
  • 1
    I'd add a log statement or breakpoint there to confirm. But the `static` is instantiated lazily and won't be called if you never reference it. – Rob Nov 15 '16 at 15:56
  • Thanks @Rob. I finally found a solution thanks to your help. I can not resume() a task if it was cancelled by the system. However, re-instanciating NSURLSession with background configuration kept inside the cancelled tasks, so I can map them all and recreate the tasks. – Gabriel.Massana Nov 15 '16 at 17:49
  • I am facing same issue for upload task. it works well for background mode but when i force kill app(with out internet) when I get network connection I am not able to resume upload task. can any one have idea how can I resume it? – Shreyank Jun 11 '18 at 12:20

1 Answers1

3

Kudos to Rob because he showed me the right path.

So after the user kills the app, the system cancels all the pending tasks.


You can see that with the system.log:

Simulator/Debug/Open System Log...

How to catch what was already ongoing?

Instantiate again your Background NSURLSession. Do it elsewhere, but I'll do it in AppDelegate for this example.

The system knows (thanks to the identifier) that it is the same Background Session that before so it maps the pending tasks.

Then retrieve all the tasks. The canceled tasks are still there

The tasks will have a error that you can check.

Error Domain=NSURLErrorDomain Code=-999 "(null)" 
UserInfo={NSErrorFailingURLStringKey=http://your.api.com/url,     
NSURLErrorBackgroundTaskCancelledReasonKey=0,        
NSErrorFailingURLKey=http://your.api.com/url}

Also, with the tasks, you will get the Request URL, so you can map your app requests and do something.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {


    // This is the code for Swift 2.x. In Swift 3.x this call is a bit different.
    NetworkingManager.backgroundManager.session.getTasksWithCompletionHandler { (data, upload, download) in

        for task in data {

            NSLog("\(task.error)")
        }

        for task in upload {

            NSLog("\(task.error)")
        }

        for task in download {

            NSLog("\(task.error)")

            let reason = task.error?.userInfo[NSURLErrorBackgroundTaskCancelledReasonKey] as? Int
            let code = task.error?.code

            if reason == NSURLErrorCancelledReasonUserForceQuitApplication &&
                code == NSURLErrorCancelled {

                NSLog("\(task.originalRequest)")
                NSLog("\(task.currentRequest?.URL)")
            }
        }
    }
}

NSURLErrorCancelledReasonUserForceQuitApplication -> The operation was canceled because the user forced the app to quit.

So we are on the right track. If someone has a better solution, please share! I do not really like the mapping solution of my requests urls.

Community
  • 1
  • 1
Gabriel.Massana
  • 8,165
  • 6
  • 62
  • 81