简体   繁体   中英

Background Network Call from Background Push

I have an application that communicates with the Apple Watch. When the main iOS app gets a remote notification, it fires off a network request using URLSession and then also sends the result to the watch.

The issue is that when the iOS app is in the background and the push notification is received, the network call is never made. I can see, via breakpoints, that the code is executed but not the code when data is received.

I do have the content-available flag set and I have also tried using the URLSessionConfiguration.background without success.

var config:URLSessionConfiguration!
var session:URLSession?

private func configureSession()
{
        self.config = URLSessionConfiguration.background(withIdentifier: "backgroundFetch")
        //self.config = URLSessionConfiguration.default
        self.config.sessionSendsLaunchEvents = true
        self.config.timeoutIntervalForRequest = 15.0
        self.config.timeoutIntervalForResource = 15.0

        self.session = URLSession(configuration: self.config, delegate: self, delegateQueue: nil)
}

You can see above that I tried it with both default and the background mode.

func getCoordinatesForID(_ trackID:String, withPassCode passCode:String, andMyID myID:String)
{
    let url = self.WEB_DOMAIN+"getcoord"
    let hash = SecurityModel.sha256(myID+trackID+passCode)!
    var request = URLRequest(url: URL(string: url)!)

    request.httpMethod = "POST"
    request.setValue("application/x-www-form-urlencoded;charset=utf-8", forHTTPHeaderField: "Content-Type")

    let postDataStr = "auth=\(hash)&id=\(myID)&trk=\(trackID)&code=\(passCode)"

    let requestBodyData = postDataStr.data(using: String.Encoding.utf8)
    request.httpBody = requestBodyData

    let postDataTask = self.session!.dataTask(with: request)
    postDataTask.taskDescription = "getCoordinates"
    postDataTask.resume()
}

The above function is called when in the background but this is where things stop. Nothing is ever received. Works fine in foreground.

I do implement the below is neither is called when in the background.

func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)

and

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)

Update:

Per the comment from Edward I did update capabilities to include "background fetch" although the documentation on downloading after a notification did not indicate this was necessary. That seems to have worked but only in part and so a problem persists.

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) 

The above is getting called but is throwing the error: "Lost connection to background transfer service" . Happens 100% of the time when in the background state but not the foreground.

 func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data)

The above which I need and is called first before the method above it, is not called at all. So overall things have progressed a bit further but still don't work in the same way as it does when in the foreground.

Solution:

The solution was to remove the timeoutIntervalForRequest and timeoutIntervalforResource Despite the fact that I never waited the 15 seconds I set before the issue resulted, removing these allowed the process to work correctly in the background. Additionally I am able to use the standard URLSessionConfiguration.default rather than the .background.

So in the end adding the "background fetch" capability and removing the timeouts resolved the issue.

I found after more tests with the ideas above that things were not working consistently. The issue is that I was using URLSessionDataTask which, as it turns out, is not support in the background. Per Apple's documentation:

Data tasks request a resource, returning the server's response as one or more NSData objects in memory. They are supported in default, ephemeral, and shared sessions, but are not supported in background sessions.

To solve this problem I had to create a URLSessionDownloadTask and use its associated delegate

func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)

With the above the network calls worked properly when the app was in the background.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM