iOS 后台 post 请求静默通知

iOS background post request on silent notification

我想问一下,当应用程序收到静默推送通知时,是否可以从应用程序发送URLPOST请求。如果可以,我怎样才能得到它?

我的应用程序成功接收静默推送通知并且当我插入phone时Xcode我能够执行url任务 (即使在背景中)并获得所需的结果。 从我的 Mac 上拔下 phone 后,phone 完全停止执行 url 任务

关于apple documentation,当静默推送通知出现时,我有30秒的时间来执行代码

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

我的静默推送通知:

{
   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)
}

已解决

目前我已将 dataTask 更新为 downloadTask,现在我能够从临时文件中成功读取服务器的答案。当应用程序在后台 运行 时,它可以正常工作。

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)
    }
}

嗨,Peter 不确定您是否想过这个问题,但基本上您必须在 URLSession 中使用 .downloadTask 而不是 .dataTask。这可能就是您当前的解决方案不起作用的原因。倾向于认为“这不是下载任务”,而只是原理图问题。将下载视为来自服务器的响应(例如 200“成功”)。您仍然可以 POST 使用此方法。