Peter Hlavatík
Peter Hlavatík

Reputation: 147

iOS background post request on silent notification

I want to ask if it's even possible to send URL POST request from app when app receive silent push notification. If it is possible how can I get it?

My application successfully receiving silent push notifications and when I have my phone plugged in Xcode I'm able to execute url task (even in background) and get the desired results. After unplugging the phone from my Mac, the phone stops executing url tasks at all.

Regarding the apple documentation, when silent push notification appears, I have 30 seconds to execute the code

Your app has 30 seconds to perform any tasks and call the provided completion handler

My silent push notification:

{
   notification: {},
   apns: {
      headers: {
          "apns-priority" : '5',
          "apns-push-type" : 'background'
      },
      payload: {
          aps: {
              "content-available" : 1,
          }
      }
   },
   topic: topic
};

AppDelegate.swift:

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    if let messageID = userInfo[gcmMessageIDKey] {
        print("Message ID: \(messageID)")
    }
    
    guard (userInfo["aps"] as? [String?: Any]) != nil else {
        Analytics.logEvent("fetch_failed", parameters: nil)
        completionHandler(.failed)
        return
    }
    
    self.emailFetch() // Here I call my function for sending POST request via URLSession
    
    print(userInfo)
    
    completionHandler(UIBackgroundFetchResult.newData)
}

SOLVED

Currently I have updated dataTask to downloadTask and now I am able to successfully read the answer from the server from temporary file. It works properly when the app is running in background.

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                 fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
    if let messageID = userInfo[gcmMessageIDKey] {
        print("Message ID: \(messageID)")
    }
    guard (userInfo["aps"] as? [String?: Any]) != nil else {
        Analytics.logEvent("fetch_failed", parameters: nil)
        completionHandler(.failed)
        return
    }
   

    if login != nil && password != nil {
        let session = URLSession.shared
        let url = URL(string: "https://....")!
        let body_values = Data(("data...").utf8)
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
        request.setValue("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/77.0.3865.120 Safari/537.36", forHTTPHeaderField: "User-Agent")
        request.httpBody = body_values
        
        print("Starting load data")

        let loadDataTask = session.downloadTask(with: request) { data, response, error in
            if let httpResponse = response as? HTTPURLResponse {
                print(httpResponse.statusCode)
                if httpResponse.statusCode == 200 {
                    if let data = data {
                        if let dataString = try? String(contentsOf: data) {
                         This is being executed only in XCode
                         My logic is here...

                            
                            completionHandler(.newData)
                        } else {
                            completionHandler(.failed)
                        }
                    }
                    else {
                        completionHandler(.failed)
                    }
                }
                else {
                    completionHandler(.failed)
                }
            }
            else {
                completionHandler(.failed)
            }
        }
        loadDataTask.resume()
    }
    else {
        completionHandler(.failed)
    }
}

Upvotes: 1

Views: 1142

Answers (1)

riverbayMark
riverbayMark

Reputation: 112

Hi Peter not sure if you ever figured this out but basically you have to use a .downloadTask instead of a .dataTask with your URLSession. That is likely why your current solution isn't working. The inclination may be to think "It's not a download task" but its just a matter of schematics. Think of download as the response from the server (e.g. 200 "Success"). You can still POST using this method.

Upvotes: 1

Related Questions