iosswiftalamofirealamofire-request

Alamofire requests while device is sleeping


My iOS app receives notification to refresh its state from our main service. Right now, we are using Alamofire to fetch the latest state and we play a continues sound when there is updated data. Our devices are locked in guided mode to stop them from turning off and provide kiosk experience.

We are making changes such that the device can go to sleep after xx minutes of inactivity. However, we ran into a problem where the device was not getting results back from Alamofire even though the request was sent successfully (based on our logs on the api side).

As I am using Alamofire 4, I have setup a singleton with backgroundsessionmanager which is how AF requests are sent now. But the challenge is that requests are sent intermittently and fail most of the time when the device is sleeping with this error:

Domain=NSURLErrorDomain Code=-997 "Lost connection to background transfer service"

Here is my code for singleton (and I have associated code in AppDelegate):

class Networking {
    static let sharedInstance = Networking()
    public var sessionManager: Alamofire.SessionManager // most of your web service clients will call through sessionManager
    public var backgroundSessionManager: Alamofire.SessionManager // your web services you intend to keep running when the system backgrounds your app will use this
    private init() {
        self.sessionManager = Alamofire.SessionManager(configuration: URLSessionConfiguration.default)
        self.backgroundSessionManager = Alamofire.SessionManager(configuration: URLSessionConfiguration.background(withIdentifier: "com.test.app"))
    }
}

Here is my code for sending the request:

let NetworkManager = Networking.sharedInstance.backgroundSessionManager

        
        DispatchQueue.main.async(execute: {
            NetworkManager.request(self.api_url, method: .post, parameters: params, encoding: JSONEncoding.default, headers: headers).responseJSON{ response in
            
                switch (response.result){
                    case .success:
                        if let jsonResp = response.result.value{
                            print("got the response")
                            print(jsonResp)
                            // parse results
                        }
                    
                    case .failure:
                        print("Network Error: \(response.error)")
                    
                }
            }
        })

I am hoping to get some help to resolve this issue as I am unable to rootcause the inconsistent behavior. I have read in some places that Apple/iOS will only allow upload/download when the app is in background mode instead of requests.


Solution

  • Yes, background sessions only permit upload and download tasks, not data tasks. They also only permit delegate-based requests, not completion handler-based requests. This answer outlines many of the considerations when doing this in conjunction with Alamofire.

    But this begs the question as to whether you really want to use a background session at all. When your app is awaken for background fetch, if you’re able to finish you request within a reasonable amount of time (e.g. 30 seconds), you should probably consider a standard session, not a background session. It’s a lot simpler.

    Do not conflate an app running in the “background” with a “background” URLSessionConfiguration: They’re completely different patterns. Just because your app is running in the background, that doesn’t mean you have to use background URLSessionConfiguration. If your app is running (whether in foreground or in the background), then a standard session is fine. You only need background session if you want it to continue after the app is suspended (or is terminated) and you’re willing to encumber yourself with all the extra overhead that background sessions entail.

    Background sessions are not intended for requests performed while the app is running in the background. They’re intended for requests that will continue after your app is suspended (and even if it eventually is terminated in the course of its natural lifecycle). That means that background sessions are ideal for slow requests that cannot be completed in a reasonable amount of time, e.g., downloading video asset, downloading many large image assets or documents, etc.

    But if you’re just performing a routine GET/POST request that will complete in a reasonable amount of time, consider not using background URLSessionConfiguration, but just do normal request and call the background fetch completion handler when your request is done (i.e., in your network request’s completion handler).