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")
}
_
すべてのターゲットに資格を設定し、プッシュを有効にしました:
バックエンドからメッセージを送信しようとすると、デバイスは何も受信しません。デリゲートは呼び出されていません。ここで何が間違っているのかわかりません。プッシュはiOS9およびAndroidデバイスで機能します。間違っている可能性のあることへのポインタはありますか?
この回答は、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()
オブジェクトのdelegate
をUserNotificationController
クラスのインスタンスに設定する必要があります。おそらく共有インスタンスを使用する必要があります。
UNUserNotificationCenter.requestAuthorization(options:completionHandler:)
メソッドを使用して通知を有効にするためにユーザーに承認を要求し、completionHandler
でgranted
値を確認します。 true
の場合、UIApplication.shared.registerForRemoteNotifications()
を呼び出してリモート通知に登録します。
現在、アプリがプッシュ通知を受信すると、いくつかの異なる状況が発生する可能性があります。ここでは、最も一般的なケースをリストしてみます。
ローカル通知:
アプリがフォアグラウンドにある場合、アプリはUserNotificationController .userNotificationCenter(_:willPresent:withCompletionHandler:)
を呼び出します。
アプリがバックグラウンド(実行中かどうか)にある場合、ユーザーが通知をタップするまで何も呼び出されません。その時点で、アプリが開き、UserNotificationController .userNotificationCenter(_:didReceive:withCompletionHandler:)
が呼び出されます。
リモート通知:
ペイロードの内容は、何が起こるかに影響します。ペイロードには3つのケースがあります。a)通常のalert
、badge
、およびsound
オプションb)content-available
オプション(1
またはtrue
)c)mutable-content
オプションを含む(1
またはtrue
に設定)。さらに、技術的にはd)content-available
とmutable-content
の両方がある場合がありますが、それは両方のケースをトリガーするだけです。
a)の場合はalert
、sound
、badge
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:)
を呼び出したりしません。ただし、アラートを表示し、サウンドを再生し、ペイロードに示されているようにバッジを更新します。
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
私はこれに丸一日苦労しました。通知を受け取ることもあれば、通知を受け取らないこともありましたが、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()
}
}
AppDelegate
デリゲートにUNUserNotificationCenter
を使用していることを確認し、application:didFinishLaunchingWithOptions
メソッドの起動時に、UserNotifications
とUserNotificationsUI
をインポートすることも忘れないでください。
次のようなコードの場合、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];