应用在后台时未接收到本地通知

我已经集成了交互式本地通知。我使用OpenAI创建了一个聊机器人。我希望在应用处于后台时,通过交互式本地通知与聊机器人进行互动。当用户响应交互式本地通知时,我会通过以下函数接收用户的响应。

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {    if response.actionIdentifier == "replyAction" {        if let textResponse = response as? UNTextInputNotificationResponse {            userQueryText = textResponse.userText            fetchGPTChatforResponse(prompt: userQueryText ?? "")        }    }    completionHandler()}

在从交互式通知接收到用户响应后,我会调用以下函数:

func fetchGPTChatforResponse(prompt: String) {    Task {        do {            let gptText = try await APIService().sendPromptToGPT(prompt: prompt)            await MainActor.run {                sendInteractiveNotification(message: gptText)            }        } catch {            print("Errrror")        }    }}

由于我的应用处于后台,我收到了以下错误:

nw_write_request_report [C2] Send failed with error “Socket is not connected”

nw_read_request_report [C1] Receive failed with error “Software caused connection abort” sendPromptToGPT

并且没有触发本地通知。我还实现了后台模式功能,如下所示。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {                          // 请求通知权限          UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in                    if granted {                        print("Notification permission granted")                    } else if let error = error {                        print("Notification permission denied: \(error.localizedDescription)")                    }                }                                UNUserNotificationCenter.current().delegate = self                let customCategory = createNotificationCategory()    UNUserNotificationCenter.current().setNotificationCategories([customCategory])                IQKeyboardManager.shared.enable = true                registerBackgroundModes()                return true            }    func registerBackgroundModes() {            print("registerBackgroundModes")            let appRefreshTaskId = "com.xyz.iOSApp.apprefresh"            let appProcessingTaskId = "com.xyz.iOSApp.fetch"                BGTaskScheduler.shared.register(forTaskWithIdentifier: appRefreshTaskId, using: nil) { task in                    self.fetchGPTChatforResponse(prompt: self.userQueryText ?? "")                    task.setTaskCompleted(success: true)                    self.scheduleAppRefresh()                }                BGTaskScheduler.shared.register(forTaskWithIdentifier: appProcessingTaskId, using: nil) { task in                //Logger.shared.info("[BGTASK] Perform bg processing \(appProcessingTaskId)")                self.fetchGPTChatforResponse(prompt: self.userQueryText ?? "")                task.setTaskCompleted(success: true)                self.scheduleBackgroundProcessing()                }        }func scheduleAppRefresh() {    print("scheduleAppRefresh")    let request = BGAppRefreshTaskRequest(identifier: "com.quilr.iOSApp.apprefresh")    request.earliestBeginDate = Date(timeIntervalSinceNow: 2 * 60)    do {        try BGTaskScheduler.shared.submit(request)    } catch {        print("Could not schedule app refresh task \(error.localizedDescription)")    }}func scheduleBackgroundProcessing() {    print("scheduleBackgroundProcessing")    let request = BGProcessingTaskRequest(identifier: "com.quilr.iOSApp.fetch")    request.requiresNetworkConnectivity = true // 如果任务需要网络处理,需要设置为true。默认值为false。    request.requiresExternalPower = true // 如果任务需要设备连接到电源,需要设置为true。默认值为false。    request.earliestBeginDate = Date(timeIntervalSinceNow: 2 * 60) // 在5分钟后处理。    do {        try BGTaskScheduler.shared.submit(request)    } catch {        print("Could not schedule image fetch: (error)")    }}

在SceneDelegate.swift中,我像这样调用了后台刷新和后台处理函数:

func sceneDidEnterBackground(_ scene: UIScene) {    // 当场景从前台过渡到后台时调用。    // 使用此方法保存数据,释放共享资源,并存储足够的场景特定状态信息    // 以便将场景恢复到当前状态。    (UIApplication.shared.delegate as? AppDelegate)?.scheduleAppRefresh()    (UIApplication.shared.delegate as? AppDelegate)?.scheduleBackgroundProcessing()    // 当应用过渡到后台时,保存应用的托管对象上下文中的更改。    (UIApplication.shared.delegate as? AppDelegate)?.saveContext()}

我还通过添加功能来启用了后台模式。但当应用处于后台时,我仍然没有收到本地通知。


回答:

您在完成工作之前就调用了委托方法提供的completionHandler,这导致iOS暂停了您的应用,从而断开了网络连接。

您需要在fetchGPTChatforResponse完成工作后再调用完成处理程序。您可以通过将Task移动到委托方法中,并使用defer来确保在所有工作完成后调用completionHandler来重构您的代码。

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {    Task {        defer {             completionHandler()        }        if response.actionIdentifier == "replyAction",           let textResponse = response as? UNTextInputNotificationResponse {            userQueryText = textResponse.userText            do {                try await fetchGPTChatforResponse(prompt:userQueryText)            }            catch {               print(error)            }        }    }}func fetchGPTChatforResponse(prompt: String) async throws {    let gptText = try await APIService().sendPromptToGPT(prompt: prompt)    await MainActor.run {        sendInteractiveNotification(message: gptText)    }}

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注