未调用iOS 10 UNUserNotificationCenterDelegate。推送通知无效

时间:2016-10-03 07:58:17

标签: ios swift apple-push-notifications

撕掉我的头发,以便在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")
    }

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

enter image description here

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

5 个答案:

答案 0 :(得分:33)

此答案适用于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:)方法中,您需要将delegate对象上的UNUserNotificationCenter.current()设置为UserNotificationController类的实例。您可能想要使用共享实例。

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

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

本地通知:

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

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

远程通知:

有效载荷的内容将影响发生的事情。有效负载有三种情况:a)正常的alertbadgesound选项b)包括content-available选项(设置为1}或true)c)包括mutable-content选项(设置为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时,您必须在有效负载中包含alert信息,否则系统会将其视为不可变,而不是调用UNNotificationServiceExtension。您修改的通知仍必须包含alert信息,否则将使用原始通知有效内容。遗憾的是,没有办法阻止通知出现给用户。

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

答案 1 :(得分:19)

尝试让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

答案 2 :(得分:1)

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

原来有两个问题。首先,我仍然有些困惑:我的目标部署版本设置为11.0,但我的项目设置为10.0。将项目更改为11.0是第一步。我对此并不完全了解,但是通知处理在10.0和11.0之间可能有所不同吗?

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

  

重要

     

您必须将委托对象分配给UNUserNotificationCenter   在您的应用完成启动之前例如,在iOS应用中,   您必须在   application(: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()
    }
}

答案 3 :(得分:0)

如果这样的代码可能没有设置UNNotificationCategory的intentIdentifiers:

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];

答案 4 :(得分:0)

除了确保为AppDelegate代理使用UNUserNotificationCenter,并在启动时在application:didFinishLaunchingWithOptions方法中设置委托,还要确保还记得导入{{1 }}和UserNotifications