web-dev-qa-db-ja.com

iOS 10 UNUserNotificationCenterDelegateは呼び出されません。プッシュ通知が機能しない

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

バックエンドからメッセージを送信しようとすると、デバイスは何も受信しません。デリゲートは呼び出されていません。ここで何が間違っているのかわかりません。プッシュはiOS9およびAndroidデバイスで機能します。間違っている可能性のあることへのポインタはありますか?

25
Kex

この回答は、UserNotificationsフレームワークを使用したiOS 10以降に関するものです。

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()オブジェクトのdelegateUserNotificationControllerクラスのインスタンスに設定する必要があります。おそらく共有インスタンスを使用する必要があります。

UNUserNotificationCenter.requestAuthorization(options:completionHandler:)メソッドを使用して通知を有効にするためにユーザーに承認を要求し、completionHandlergranted値を確認します。 trueの場合、UIApplication.shared.registerForRemoteNotifications()を呼び出してリモート通知に登録します。

現在、アプリがプッシュ通知を受信すると、いくつかの異なる状況が発生する可能性があります。ここでは、最も一般的なケースをリストしてみます。

ローカル通知:

アプリがフォアグラウンドにある場合、アプリはUserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:)を呼び出します。

アプリがバックグラウンド(実行中かどうか)にある場合、ユーザーが通知をタップするまで何も呼び出されません。その時点で、アプリが開き、UserNotificationController .userNotificationCenter(_:didReceive:withCompletionHandler:)が呼び出されます。

リモート通知:

ペイロードの内容は、何が起こるかに影響します。ペイロードには3つのケースがあります。a)通常のalertbadge、およびsoundオプションb)content-availableオプション(1またはtrue)c)mutable-contentオプションを含む(1またはtrueに設定)。さらに、技術的にはd)content-availablemutable-contentの両方がある場合がありますが、それは両方のケースをトリガーするだけです。

a)の場合はalertsoundbadge info:

これは、ローカル通知と同じように機能します。

b)content-available == true:

アプリがフォアグラウンドにある場合、UserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:)が呼び出されます。

アプリがバックグラウンドにある場合(実行中かどうかに関係なく)、UserNotificationControllerクラスのメソッドの1つではなく、AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:)が呼び出されます。

c)mutable-content == true:

アプリケーションにUNNotificationServiceExtensionを追加した場合、通知を処理し、コンテンツを変更できます。これは、メインアプリケーションの状態に関係なく発生します。 (オプションで変更された)通知がユーザーによってタップされた場合、それは上記のローカル通知のように処理されます。

UNNotificationServiceExtensionがない場合、通知は上記の通常のリモート通知のように扱われます。

追記:

mutable-contentを使用する場合、ペイロードにalert情報を含める必要があります。そうしないと、システムはそれを不変として扱い、UNNotificationServiceExtensionを呼び出しません。変更した通知にはalert情報を含める必要があります。そうしないと、元の通知ペイロードが使用されます。悲しいことに、通知がユーザーに表示されるのを防ぐ方法はありません。

content-availableを使用する場合、ユーザーが最後に使用したときにアプリを強制終了した場合、システムはアプリを再起動したり、AppDelegate.application(_:didReceiveRemoteNotification:fetchCompletionHandler:)を呼び出したりしません。ただし、アラートを表示し、サウンドを再生し、ペイロードに示されているようにバッジを更新します。

41
Dave Wood

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
20
PO Bengtsson

私はこれに丸一日苦労しました。通知を受け取ることもあれば、通知を受け取らないこともありましたが、userNotificationCenter(_:willPresent:completionHandler:)コールバックをトリガーすることはできませんでした。

2つの問題があることが判明しました。最初は、まだ少し混乱しています。ターゲットデプロイメントバージョンは11.0に設定されていましたが、プロジェクトは10.0に設定されていました。プロジェクトを11.0に変更することが最初のステップでした。私はこれを完全には理解していませんが、10.0と11.0で通知処理に何らかの違いがあるのでしょうか?

2番目の部分は、通知センターの代理人でした。 Appleの ドキュメントに注意してください :-

重要

アプリの起動が完了する前に、デリゲートオブジェクトをUNUserNotificationCenterオブジェクトに割り当てる必要があります。たとえば、iOSアプリでは、アプリデリゲートのapplication(:willFinishLaunchingWithOptions :)またはapplication(:didFinishLaunchingWithOptions :)メソッドで割り当てる必要があります。これらのメソッドが呼び出された後にデリゲートを割り当てると、着信通知を見逃す可能性があります。

私は別の「通知マネージャー」クラスに設定していました。このクラスには、コールバックも(デリゲートプロトコル実装として)配置されていました。これは、アプリデリゲートのインスタンス変数としてインスタンス化しました。これは、これが早期に作成され、問題を引き起こさないことを前提としています。

しばらくインスタンス化などをいじりましたが、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()
    }
}
5
Echelon

AppDelegateデリゲートにUNUserNotificationCenterを使用していることを確認し、application:didFinishLaunchingWithOptionsメソッドの起動時に、UserNotificationsUserNotificationsUIをインポートすることも忘れないでください。

0
Lee Probert

次のようなコードの場合、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];
0
Slemon