【问题标题】:iOS 10 UNUserNotificationCenterDelegate not called. push notifications not working未调用 iOS 10 UNUserNotificationCenterDelegate。推送通知不起作用
【发布时间】:2017-02-11 02:53:43
【问题描述】:

为了让推送通知在 iOS10 中工作,我抓狂了。当前设置:

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

if #available(iOS 10.0, *) {

            let center = UNUserNotificationCenter.current()
            center.delegate = self
            center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in

                if error == nil {
                    print("DID REQUEST THE NOTIFICATION")
                    UIApplication.shared.registerForRemoteNotifications()
                }
            }
            print("DID SET DELEGATE")
        }

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data):

print("DID REGISTER FOR A REMOTE NOTIFICATION AND THE TOKEN IS \(deviceToken.base64EncodedString())"           
let request = UpdatePushNotificationSubscription_Request(deviceToken: deviceToken)
updatePushNotificationSubscriptionWorker.updateSubscription(request)

我已检查令牌是否正确上传到后端,并且确实匹配。

我也实现了:

    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

        print("GOT A NOTIFICATION")

    }


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

        //This is for the user tapping on the notification
        print("GOT A NOTIFICATION")
    }

我已为所有目标设置了权利并启用了推送:

现在,当我尝试从后端发送消息时,设备什么也没有收到。没有召集代表。不知道我在这里做错了什么。 Push 适用于 iOS9 和 android 设备。任何指向我可能做错了什么的指针?

【问题讨论】:

  • 这不是一个真正的答案,因为我仍然和你有同样的问题。尝试检查您的设备令牌是否被正确解析,因为对我来说,截至 ios10,它不是。但是我确实修复了它,但我仍然没有调用我的代表
  • 您找到解决方案了吗?
  • 有人对此有解决方案吗?自 iOS 10 以来,我也遇到了同样的问题 - 现在在 iOS 10.1.1
  • 您的问题解决了吗?即使我面对
  • 我认为问题在于您没有在 userNotificationCenter 方法中调用 completionHandler。只需添加并测试。

标签: ios swift apple-push-notifications


【解决方案1】:

此答案适用于 iOS 10+,使用 UserNotifications 框架。

您需要一个符合UNUserNotificationCenterDelegate 协议的类。如果您为此创建一个新课程,或者将其添加到您的AppDelegate 课程中,这并不重要。不过,我建议创建一个专门的课程。出于此答案的目的,假设您为它创建了一个 UserNotificationController 类。

该类可以有以下方法:

optional func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)

optional func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)

然后在您的AppDelegate.application(_:didFinishLaunchingWithOptions:) 方法中,您需要将UNUserNotificationCenter.current() 对象上的delegate 设置为您的UserNotificationController 类的一个实例。您可能希望使用共享实例。

请求用户授权以使用UNUserNotificationCenter.requestAuthorization(options:completionHandler:) 方法启用通知,并在completionHandler 中检查granted 值。如果是true,请拨打UIApplication.shared.registerForRemoteNotifications()注册远程通知。

现在,当应用收到推送通知时,可能会发生几种不同的情况。我将在此处尝试列出最常见的情况。

本地通知:

如果应用在前台,应用会调用UserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:)

如果应用程序在后台(运行与否),则在用户点击通知之前不会调用任何内容,此时,应用程序将打开并调用UserNotificationController .userNotificationCenter(_:didReceive:withCompletionHandler:)

远程通知:

有效载荷的内容会影响发生的事情。有效载荷有三种情况,a) 只是普通的 alertbadgesound 选项 b) 包括 content-available 选项(设置为 1true) c) 包括 @ 987654344@ 选项(设置为1true)。另外,从技术上讲,d) 你同时拥有 content-availablemutable-content,但这只会触发这两种情况。

对于 a) 只需 alertsoundbadge 信息:

这与本地通知的工作方式相同。

对于 b) content-available == true:

如果应用在前台,则调用UserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:)

如果应用在后台(运行与否),则调用AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:),而不是UserNotificationController 类中的方法之一。

对于 c) mutable-content == true:

如果您在应用程序中添加了UNNotificationServiceExtension,它将处理通知并可以修改内容。无论您的主应用程序的状态如何,都会发生这种情况。如果用户点击了(可选修改的)通知,则会像上面的本地通知一样处理它。

如果没有UNNotificationServiceExtension,该通知将被视为上面的普通远程通知。

附加说明:

使用mutable-content时,必须在payload中包含alert信息,否则系统会将其视为不可变的,不会调用您的UNNotificationServiceExtension。您修改后的通知仍必须包含alert 信息,否则将使用原始通知有效负载。遗憾的是,没有办法阻止通知向用户显示。

在使用content-available时,如果用户上次使用时强行退出应用,系统不会重新启动应用或调用AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:)。尽管它仍会显示任何警报、播放声音并按照有效负载中的指示更新徽章。

【讨论】:

  • 很棒的答案
  • 优秀的答案!这个解释应该包含在 Apple 的开发者文档中。
  • 多年来我看到的与 PN 处理相关的更好答案之一。干得好!
  • @ShinehahGnolaum 它应该可以工作。 CloudKit 使用相同的 UserNotifications 框架。
  • 在 2020 年这个答案仍然很棒,@DaveWood 非常感谢你
【解决方案2】:

尝试让您的 AppDelegate 类实现 UNUserNotificationCenterDelegate 协议,而不是实现该协议的单独类。

我为代表准备了一个单独的课程,但它不起作用。这是我的代码在运行时的样子:

import UIKit
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

var window: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application 

    UIApplication.shared.registerForRemoteNotifications()

    let center = UNUserNotificationCenter.current()
    center.delegate = self //DID NOT WORK WHEN self WAS MyOtherDelegateClass()

    center.requestAuthorization(options: [.alert, .sound, .badge]) {
        (granted, error) in
            // Enable or disable features based on authorization.
            if granted {
                // update application settings
            }
    }

    return true
}

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

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive: UNNotificationResponse,
                            withCompletionHandler: @escaping ()->()) {
    withCompletionHandler()
}

// and so forth for your other AppDelegate stuff

【讨论】:

  • 由于 UNUserNotificationCenter.current().delegate 很弱,你必须自己让它活着。这就是为什么 AppDelegate 在这里是一个很好的候选人。您还可以为此构建一个类,并使其在您的 AppDelegate 或其他任何地方保持活力:)
  • @PO Bengtsson 和 @zarghol 谢谢!你让我明白为什么我的 UNUserNotificationCenterDelegate 方法没有被调用。我有一个单独的类来处理通知。我怎样才能设法让这个类保持活动状态,以确保调用委托方法?
  • 你可以通过简单地使用你的类的单例来做到这一点,或者只是在某处保留你的类的强引用(appdelegate,你当前的视图控制器......)
  • 非常感谢,你拯救了我的一天!
【解决方案3】:

我为此苦苦挣扎了一整天。有时我收到通知,有时没有,但我永远无法触发 userNotificationCenter(_:willPresent:completionHandler:) 回调。

原来有两个问题。第一个我仍然有点困惑:我的目标部署版本设置为 11.0,但我的项目设置为 10.0。将项目更改为 11.0 是第一步。我不完全理解这一点,但 10.0 和 11.0 之间的通知处理可能存在一些差异?

第二部分是通知中心委托。我注意到苹果的note in the docs:-

重要

您必须将您的委托对象分配给 UNUserNotificationCenter 在您的应用程序完成启动之前创建对象。例如,在 iOS 应用程序中, 您必须在 应用程序(:willFinishLaunchingWithOptions:) 或 应用程序的 application(:didFinishLaunchingWithOptions:) 方法 代表。在调用这些方法之后分配一个委托可能 导致您错过收到的通知。

我一直在设置一个单独的“通知管理器”类,这也是回调所在的位置(作为委托协议实现)。我已经在我的应用委托中将它实例化为实例 var,假设它会在早期创建并且不会导致问题。

我在实例化等方面搞砸了一段时间,但只有当我在 application(_:didFinishLaunchingWithOptions:) 方法中设置委托并在应用程序委托中实现委托回调时,我才设法修复它。

所以我的代码基本上变成了:-

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

    // You MUST do this HERE and nowhere else!
    UNUserNotificationCenter.current().delegate = self

    // other stuff

    return true
}

extension AppDelegate: UNUserNotificationCenterDelegate {

    // These delegate methods MUST live in App Delegate and nowhere else!

    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        if let userInfo = notification.request.content.userInfo as? [String : AnyObject] {
        }
        completionHandler(.alert)
    }

    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        if let userInfo = response.notification.request.content.userInfo as? [String : AnyObject] {
        }
        completionHandler()
    }
}

【讨论】:

  • UNUserNotificationCenter.current().delegate = self 这个位置使它可以通过应用程序与我交谈。谢谢。
  • 这对我真的很有帮助,感谢您发布此信息!有同样的问题,使用了通知管理器类。
  • 兄弟,非常感谢,大约一年前,这个答案救了我,今天又救了我;没有人告诉你UNUserNotificationCenter.current().delegate = self
  • 谢谢兄弟。拯救了这一天
  • 应用在后台时没有调用这些方法,我做错了什么?
【解决方案4】:

可能没有设置UNNotificationCategoryintentIdentifiers,如果这样的代码:

UNNotificationCategory* expiredCategory = [UNNotificationCategory
                                               categoryWithIdentifier:@"TIMER_EXPIRED"
                                               actions:@[snoozeAction, stopAction]
                                               intentIdentifiers:@[]
                                               options:UNNotificationCategoryOptionCustomDismissAction];

它不会调用UNUserNotificationCenter的委托方法,所以你必须像这样设置intentIdentifiers:

UNNotificationCategory* expiredCategory = [UNNotificationCategory
                                               categoryWithIdentifier:@"TIMER_EXPIRED"
                                               actions:@[snoozeAction, stopAction]
                                               intentIdentifiers:@[@"a",@"b"]
                                               options:UNNotificationCategoryOptionCustomDismissAction];

【讨论】:

    【解决方案5】:

    除了确保将AppDelegate 用于UNUserNotificationCenter 委托,并在启动时在application:didFinishLaunchingWithOptions 方法中设置委托外,请确保您还记得导入UserNotificationsUserNotificationsUI

    【讨论】:

    • Lee,为什么你真的需要 UI 的 UserNotificationsUI ??
    • 诚实吗?现在想不起来了。
    • gotchya 李!对于在这里使用谷歌搜索的任何人,我很确定您不需要它:通常没有它也可以正常工作!您必须导入UserNotifications
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-22
    • 2020-10-05
    相关资源
    最近更新 更多