为啥 userNotificationCenter didReceive 没有被解雇?

Posted

技术标签:

【中文标题】为啥 userNotificationCenter didReceive 没有被解雇?【英文标题】:Why userNotificationCenter didReceive is not fired?为什么 userNotificationCenter didReceive 没有被解雇? 【发布时间】:2018-11-24 16:44:18 【问题描述】:

这是我的代码的一部分。我想使用UNUserNotificationCenterUNUserNotificationCenterDelegate 来处理通知事件。

此代码在应用处于前台状态时捕获通知事件。但是"didReceive" 不会因为后台状态而被触发。

func application(_ application: UIApplication,
                         didFinishLaunchingWithOptions launchOptions:
            [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool 
            UNUserNotificationCenter.current().delegate = self
    application.registerForRemoteNotifications()
    return true
        
        func userNotificationCenter(_ center: UNUserNotificationCenter,
                                    willPresent notification: UNNotification,
                                    withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
        
            print("willPresent") /// This works
            completionHandler([.alert, .badge, .sound])
        
        func userNotificationCenter(_ center: UNUserNotificationCenter,
                                    didReceive response: UNNotificationResponse,
                                    withCompletionHandler completionHandler: @escaping () -> Void) 
            print("didReceive") /// This doesn't work
            completionHandler()
        

但如果我不使用UNUserNotificationCenter.current().delegate = self,委托方法会在后台正确触发。

func application(_ application: UIApplication,
                     didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                     fetchCompletionHandler completionHandler: @escaping FetchCompletionHandler) 
        print("didReceiveRemoteNotification... \(userInfo)")

如何使用“didReceive”?我想在后台处理通知。

【问题讨论】:

【参考方案1】:

application(_:didReceiveRemoteNotification:fetchCompletionHandler:) 在应用程序接收到静默推送通知时被调用。当应用程序处于后台状态时,可以发送静默推送通知,ios 唤醒应用程序执行用户不可见的后台处理。

静默推送通知将 content-available 标志设置为 1。

静默推送通知不应包含警报、徽章或声音。静默推送并不意味着对用户可见,它只是向应用程序提示新的远程内容可用。

从推送通知负载中删除content-available 标志将导致iOS 将其作为常规通知处理。将调用用户通知中心委托方法而不是 application(_:didReceiveRemoteNotification:fetchCompletionHandler:),但您的应用程序将无法执行通知触发的后台处理。

您可以使用this tool 验证推送通知负载的内容是否存在此类问题

【讨论】:

这似乎不是这种情况(不再):“要支持后台更新通知,请确保有效负载的 aps 字典包含值为 1 的内容可用键。如果有是与后台更新一起出现的用户可见更新,您可以根据需要在 aps 字典中设置警报、声音或徽章键。”来自developer.apple.com/library/archive/documentation/…【参考方案2】:

这就是我在应用程序中处理推送通知的方式。我认为您需要实现所有这些方法以在前台和后台模式下处理所有 iOS 版本。

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 

    if #available(iOS 10.0, *) 
        let center  = UNUserNotificationCenter.current()
        center.delegate = self
        center.requestAuthorization(options: [.sound,.alert,.badge], completionHandler:  (granted, error) in
            if error == nil 
                DispatchQueue.main.async 
                    application.registerForRemoteNotifications()
                
            
        )
    
    else 
        let notificationTypes: UIUserNotificationType = [UIUserNotificationType.alert, UIUserNotificationType.badge, UIUserNotificationType.sound]
        let pushNotificationSettings = UIUserNotificationSettings(types: notificationTypes, categories: nil)
        application.registerUserNotificationSettings(pushNotificationSettings)
        application.registerForRemoteNotifications()
    



func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) 
    let deviceTokenString = deviceToken.reduce("", $0 + String(format: "%02X", $1))
    print(deviceTokenString)


func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) 
    print("Failed to get token; error: \(error)")


@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) 
    completionHandler([.alert,.sound])
     //do sth


@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) 
     //do sth


// for iOS < 10
func application(_ application: UIApplication, didReceive notification: UILocalNotification) 


func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) 

【讨论】:

【参考方案3】:

有UNUserNotificationCenterDelegate的方法:

willPresent:当您的应用处于前台时,当您收到通知时会调用此方法。如果应用程序在后台,则此方法不会调用。

didRecieve:当用户点击通知时调用此方法。

在后台状态下,当用户点击通知时,只会调用“didRecieve”。

【讨论】:

以上是关于为啥 userNotificationCenter didReceive 没有被解雇?的主要内容,如果未能解决你的问题,请参考以下文章

选择通知操作时不会调用 userNotificationCenter(_:didReceive:withCompletionHandler:)

从 userNotificationCenter 检索通知类型:didReceiveNotificationResponse:withCompletionHandler:

userNotificationCenter didReceive 响应包含空通知(watchOS)

iOS 将通知对象发送到 UserNotificationCenter 和 didFinishLaunchingWithOptions

通知不会触发 macOS Big Sur 11.6 上的 userNotificationCenter

单元测试 UNUserNotificationCenterDelegate 方法