You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

应用关闭时点击UNNotificationAction如何保存数据到UserDefaults?

问题:应用完全关闭时点击通知操作无法保存数据到UserDefaults

应用处于前台或后台状态时,userNotificationCenter(_:didReceive:withCompletionHandler:)能正常触发,数据可成功保存至UserDefaults;但应用完全关闭时,点击通知的操作按钮,数据无法保存,无任何响应。

相关代码

通知注册代码:

UNUserNotificationCenter.current().delegate = self
        
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound, .criticalAlert]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions, completionHandler: { (granted, error) in
        if granted {
            
        }
    })
        
let PKW = UNNotificationAction(identifier: "PKW", title: "Komme per PKW", options: .foreground)
let Fuß = UNNotificationAction(identifier: "Fuß", title: "Komme per Fuß", options: .foreground)
let Rad = UNNotificationAction(identifier: "Rad", title: "Komme per Rad", options: .foreground)
let nicht = UNNotificationAction(identifier: "Nicht", title: "Komme per Komme nicht", options: .foreground)
let category = UNNotificationCategory(identifier: "ComeBy", actions: [PKW, Fuß, Rad, nicht], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])

application.registerForRemoteNotifications()

通知代理方法:

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            willPresent: UNNotification,
                            withCompletionHandler: @escaping (UNNotificationPresentationOptions)->()) {
    withCompletionHandler([.alert, .sound, .badge])
}

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive response: UNNotificationResponse,
                            withCompletionHandler: @escaping ()->()) {
    let eventData = response.actionIdentifier
    switch eventData {
    case "PKW", "Fuß", "Rad", "Nicht":
        UserDefaults.standard.set(eventData, forKey: prefixedKey(UserDefaultsKeys.comeBy.key))
    default:
        break
    }

    
    withCompletionHandler()
}

问题原因分析

  1. 代理设置时机过晚:应用完全关闭后冷启动时,系统会先触发通知回调,若UNUserNotificationCenter的代理在回调触发后才设置,didReceive方法就不会被调用。
  2. 进程提前终止:冷启动时,若未确保数据写入完成就调用withCompletionHandler(),系统可能在UserDefaults写入完成前终止应用进程,导致数据丢失。
  3. 推送payload不匹配:若推送通知的payload未指定正确的category字段,系统无法匹配到对应的操作按钮,回调不会触发。

解决方案

1. 提前设置通知中心代理

将代理设置代码移至application(_:didFinishLaunchingWithOptions:)的最开头,确保系统触发回调前代理已生效:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // 优先设置代理
    UNUserNotificationCenter.current().delegate = self
    
    // 后续的授权、类别注册、远程通知注册逻辑
    let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound, .criticalAlert]
    UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
        if granted {
            // 授权成功逻辑
        }
    }
    
    let PKW = UNNotificationAction(identifier: "PKW", title: "Komme per PKW", options: .foreground)
    let Fuß = UNNotificationAction(identifier: "Fuß", title: "Komme per Fuß", options: .foreground)
    let Rad = UNNotificationAction(identifier: "Rad", title: "Komme per Rad", options: .foreground)
    let nicht = UNNotificationAction(identifier: "Nicht", title: "Komme per Komme nicht", options: .foreground)
    let category = UNNotificationCategory(identifier: "ComeBy", actions: [PKW, Fuß, Rad, nicht], intentIdentifiers: [], options: [])
    UNUserNotificationCenter.current().setNotificationCategories([category])
    
    application.registerForRemoteNotifications()
    
    return true
}

2. 确保数据写入完成后调用completionHandler

在冷启动场景下,可通过synchronize()确保UserDefaults数据写入完成(官方虽不推荐,但冷启动时可临时使用),再调用withCompletionHandler():

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler: @escaping ()->()) {
    let eventData = response.actionIdentifier
    switch eventData {
    case "PKW", "Fuß", "Rad", "Nicht":
        UserDefaults.standard.set(eventData, forKey: prefixedKey(UserDefaultsKeys.comeBy.key))
        // 确保数据写入完成
        UserDefaults.standard.synchronize()
    default:
        break
    }
    
    // 所有操作完成后再调用completionHandler
    withCompletionHandler()
}

3. 验证推送payload的category字段

确保推送通知的payload中指定了正确的category值"ComeBy",示例payload:

{
  "aps": {
    "alert": "Test Notification",
    "category": "ComeBy",
    "sound": "default"
  }
}

内容的提问来源于stack exchange,提问作者lawayben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 23:13:17