iOS10から UserNotifications が加わったことにより、ローカル通知の扱いが少し変わっています。
今回はiOS10で通知済みのローカル通知(通知センターに表示されたもの)が、通知をタップせずに起動した場合にiOS9までと同じ方法では 消えない ことに気がついたのでそれをまとめておきます。
(※ちなみに通知センターから通知をタップして起動した場合は消えてくれます。)
iOS9まで
iOS9までは、通知センターの通知をタップして起動しなかった場合に、
以下の実装を起動後任意のタイミングで行うことで、通知前/通知後のローカル通知に関わらず削除することができました。
UIApplication.shared.cancelAllLocalNotifications()
iOS10から
iOS10からは、上記の方法では、通知前のローカル通知しか消えなくなっています。
(iOS10だとこのメソッドがdeprecatedになっています…。)
@available(iOS, introduced: 4.0, deprecated: 10.0, message: "Use UserNotifications Framework's -[UNUserNotificationCenter removeAllPendingNotificationRequests]")
open func cancelAllLocalNotifications()
iOS10で通知済みのものを削除する
UserNotifications frameworkでは、ローカル通知に関して通知前のものを pending
、 通知後のものを delivered
として扱っているようです。
今回は、 delivered
になった通知を削除したいので、以下のように UNUserNotificationCenter
を使って削除処理を書きます。
今回は全てを削除するものと、identifier
を見て削除するもの、userInfo
を見て削除するものそれぞれのサンプルを出してみました。
let center = UNUserNotificationCenter.current()
// 全ての通知済みの通知を削除する
center.removeAllDeliveredNotifications()
// notification.requestのIDで絞って消す
center.getDeliveredNotifications { notifications in
let identifiers = notifications
.filter { $0.request.identifier == "foobar"}
.map { $0.request.identifier }
center.removeDeliveredNotifications(withIdentifiers: identifiers)
}
// notificationに設定したuserInfoで比較する場合
// notification.request.contentにuserInfoが渡るのでそれを使って削除する
center.getDeliveredNotifications { notifications in
let identifiers = notifications
.filter { notification in
let userInfo = notification.request.content.userInfo
return castOrNil(userInfo["identifier"]) == "foobar"
}.map { $0.request.identifier }
center.removeDeliveredNotifications(withIdentifiers: identifiers)
}
// Helper function
func castOrNil<T, U>(_ value: T?) -> U? {
return value as? U
}
通知前のものは
一応 UIApplication.shared.cancelAllLocalNotifications()
でもpendingなものは消えてくれますが、iOS10を対象にするとdeprecatedになるので、やはり同じようにこんな感じで処理を書いてあげます。
let center = UNUserNotificationCenter.current()
// 全てのpendingな通知を削除する
center.removeAllPendingNotificationRequests()
// requestのIDで絞って消す
center.getPendingNotificationRequests { requests in
let identifiers = requests
.filter { $0.identifier == "foobar"}
.map { $0.identifier }
center.removePendingNotificationRequests(withIdentifiers: identifiers)
}
// notificationに設定したuserInfoで比較する場合
// request.contentにuserInfoが渡るのでそれを使って削除する
center.getPendingNotificationRequests { requests in
let identifiers = requests
.filter { request in
let userInfo = request.content.userInfo
return castOrNil(userInfo["id"]) == "12345"
}.map { $0.identifier }
center.removePendingNotificationRequests(withIdentifiers: identifiers)
}
最後に
iOS10ではなるべくUserNotificationsを使うようにすれば変なところでハマらずに済みそうです。