首页 > 解决方案 > 应用程序在后台时来自 iOS 推送通知操作的 Http 请求

问题描述

我的 iOS 应用程序可以接收带有操作按钮的推送通知:

使用操作按钮推送通知

按钮点击通过 UrlSession 和数据任务发送 post http 请求。当应用程序暂停或未运行时,它运行良好。但是当应用程序在后台时它不起作用,例如当用户刚刚从底部向上滑动(或按下主页按钮)时。推送操作句柄,但未发送 http 请求。

从我的 iPhone 的控制台 os_logs 中,我看到 UrlSession 无法从后台建立连接并抛出错误代码 = -1005“网络连接丢失。”。只要我杀死应用程序,它就可以。我尝试了不同的 url 会话配置、后台 url 会话、后台任务,但没有任何效果。我发现的唯一解决方法是使用exit(0)fromapplicationDidEnterBackground方法,但强烈建议不要以编程方式杀死应用程序。

问题:当应用程序在后台时,如何通过推送通知操作建立 http 连接?

我的代码:

class NotificationService: NSObject, UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // notification processing if app is in foreground
        ...
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let requestId = String(describing: response.notification.request.content.userInfo["requestId"] ?? "")
        switch response.actionIdentifier {
        case "CONFIRM_ACTION":
            confirmAuthenticationRequest(requestId: requestId, isConfirmed: true)
        case "REJECT_ACTION":
            confirmAuthenticationRequest(requestId: requestId, isConfirmed: false)
        default:
            // on notification tap
            ...
        }
        completionHandler()
    }

private func confirmAuthenticationRequest(requestId: String, isConfirmed: Bool) {
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        let json: [String: Any] = [
            "requestId": requestId,
            "deny": !isConfirmed
        ]
        request.httpBody = try? JSONSerialization.data(withJSONObject: json)
        request.addValue("application/json", forHTTPHeaderField: "content-type")
        
        let dataTask = urlSession.dataTask(with: request)
        dataTask.resume()
    }
}

标签: iosswiftapple-push-notificationsbackground-process

解决方案


最后我找到了答案。推送通知操作不稳定的原因是completionHandleruserNotificationCenterDidReceiveResponse方法调用的错误方式。当执行像 http 请求这样的异步操作时,您必须completionHandler 在操作完成后(而不是在操作调用之后)并从主线程调用。这是工作示例:

class NotificationService: NSObject, UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let requestId = String(describing: response.notification.request.content.userInfo["requestId"] ?? "")
        switch response.actionIdentifier {
        case "CONFIRM_ACTION":
            confirmAuthenticationRequest(requestId: requestId, isConfirmed: true, completion: completionHandler)
        case "REJECT_ACTION":
            confirmAuthenticationRequest(requestId: requestId, isConfirmed: false, completion: completionHandler)
        default:
            // on notification tap
            ...
            completionHandler()
        }
    }

private func confirmAuthenticationRequest(requestId: String, isConfirmed: Bool, completion: @escaping () -> Void) {
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        let json: [String: Any] = [
            "requestId": requestId,
            "deny": !isConfirmed
        ]
        request.httpBody = try? JSONSerialization.data(withJSONObject: json)
        request.addValue("application/json", forHTTPHeaderField: "content-type")
        
        let dataTask = urlSession.dataTask(with: request) { _, _, _ in
            DispatchQueue.main.async {
                completion()
            }
        }
        dataTask.resume()
    }
}

推荐阅读