iOS10の UserNotifications Framework で、UNNotificationの状態と、通知の削除についてさっとまとめてみました。
若干言い回しが曖昧かもしれませんが、ご了承ください。
実行環境
- Xcode8 beta (Swift 3.0 preview-1)
情報としては、Apple Developerで公開されている情報を基にしています。
また、まだBeta段階ですので、今後変わる可能性はあります。スクリーンショットは掲載しておりません。
通知の状態
通知には、Pending
とDelivered
の2つの状態があります。
Pending
: 通知がまだ発火していない状態Delivered
: 通知が発火したが、まだユーザーが見ていない(タップしたりしてdismissしていない)状態
UNUserNotificationCenter
に、UNNotificationRequest
を追加することで、その通知はまずPending
になります。
その後、triggerで指定した条件を満たし、発火することで、Delivered
に変わります。
そして、その通知を開いたりすることで、この状態からはずれ、通知が完了します。
それぞれの状態にある通知を取得する
Pending
またはDelivered
になっている通知の一覧を取得することができます。
それぞれ、UNUserNotificatoinCenterの、
public func getPendingNotificationRequests(completionHandler: ([UNNotificationRequest]) -> Swift.Void)
public func getDeliveredNotifications(completionHandler: ([UNNotification]) -> Swift.Void)
を使います。
UNUserNotificationCenter.current().getPendingNotificationRequests {
print("Pending requests :", $0)
}
UNUserNotificationCenter.current().getDeliveredNotifications {
print("Delivered notifications :", $0)
}
注意したいのが、Pending
の場合は、UNNotificationRequest
型の配列で、Delivered
の場合は、UNNotification
型の配列になっています。
ちなみに、UNNotificationRequest
は生成時のidentifierが取得でき、UNNotification
は、その通知の基となっているrequestが取得できるので、
UNUserNotificationCenter.current().getPendingNotificationRequests {
print("Pending request identifiers :", $0.map { $0.identifier })
}
UNUserNotificationCenter.current().getDeliveredNotifications {
print("Delivered notification identifiers :", $0.map { $0.request.identifier })
}
こんな感じで通知リクエストのidentifierを取得することができます。
それぞれの状態になっている特定の通知を削除する
Pending
、Delivered
になっている特定の通知を削除したい場合は、
public func removePendingNotificationRequests(withIdentifiers identifiers: [String])
public func removeDeliveredNotifications(withIdentifiers identifiers: [String])
を使って、UNNotificationRequest
のidentifierを渡して削除します。
let requestIdentifier = "SampleNotificationRequest"
let request = UNNotificationRequest(identifier: requestIdentifier,
content: content,
trigger: trigger)
// ...
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ["SampleNotificationRequest"])
Pending
になっているものを削除すれば、通知は発火せずに終了し、
Delivered
になっているものを削除すれば、通知されたものが通知センターから消えます。
また、identifierは配列で渡すので、複数まとめて削除することもできます。
例えば、Pending
のうち、Hoge_
をprefixにもつ通知だけ削除したい場合は、今までのを組み合わせて
UNUserNotificationCenter.current().getPendingNotificationRequests { requests in
let identifiers = requests.map({ $0.identifier }).filter({ $0.hasPrefix("Hoge_") })
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: identifiers)
}
こんな感じで削除ができます。
また、それぞれの状態にない通知のidentifierを渡しても、エラーになったりはしません。
それぞれの状態の全ての通知を一括で削除する
それぞれ、removeAllPendingNotificationRequests
、removeAllDeliveredNotifications
を呼び出してあげることで、identifierに拘らず、一括で削除することができます。
// Pendingのものを全て削除
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
// Deliveredのものを全て削除
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
あるidentifierに関する通知を完全に削除する
Pending
になっているのか、Delivered
になっているのかわからないけど、とりあえず綺麗に削除して新たに通知を作成したい場合や、
どちらの状態に拘らず通知を削除したい場合は、
こんな感じでextensionを用意しておけば、2行書く手間が省けます。
extension UNUserNotificationCenter {
func removeNotificationsCompletely(withIdentifiers identifiers: [String]) {
self.removePendingNotificationRequests(withIdentifiers: identifiers)
self.removeDeliveredNotifications(withIdentifiers: identifiers)
}
}
// ...
let identifiers = ["Hoge_Notification1", "Hoge_Notification2"]
UNUserNotificationCenter.current().removeNotificationsCompletely(withIdentifiers: identifiers)
これで通知が被ることも、通知センターに同じ通知が2つ出ることもなくなります。
ただ、Delivered
の通知まで消してしまうので、タイミングは考えないとですね。
最後に
今まで通知が発火する前なのか、発火したあとなのかをあまり意識していなかったのですが、今回からPending
とDelivered
と区別されてAPIが提供されていることで、意識できるようになった気がします。
ちなみに、notification.state
や、request.state
みたいに、状態をプロパティで直に取得することはできないようです。