Usernotification 框架徽章不增加
Posted
技术标签:
【中文标题】Usernotification 框架徽章不增加【英文标题】:Usernotification framework badge does not increase 【发布时间】:2018-09-14 01:07:45 【问题描述】:我在我的应用程序中使用UserNotification
框架并发送本地通知(不是推送通知),我想将徽章设置为收到的通知数量,所以我所做的就是将收到的通知数量设置为user default 然后我尝试将值分配给徽章以获得徽章编号,但徽章编号不会增加。这是我下面的代码
设置收到通知的值
center.getDeliveredNotifications notification in
UserDefaults.standard.set(notification.count, forKey: Constants.NOTIFICATION_COUNT)
print("notification.count \(notification.count)")
print(".count noti \(UserDefaults.standard.integer(forKey: Constants.NOTIFICATION_COUNT))")
这会准确打印收到的通知数量,当我决定将其设置为我的徽章时,它只显示 1
content.badge = NSNumber(value: UserDefaults.standard.integer(forKey: Constants.NOTIFICATION_COUNT))
我不知道为什么价值不会每次都增加。任何帮助将不胜感激。
或者,如果可以始终在应用中的任何位置更新徽章。
【问题讨论】:
我没有看到任何一行表明某个值已增加或更改。 我错过了什么? 你没有解释为什么你认为价值会增加。你没有增加它,那么你期望它会增加什么? 我如何获得徽章以显示通知数量。我在文档上什么都找不到 您要设置哪个徽章?您在 ios 主屏幕上看到的应用程序图标徽章? 【参考方案1】:像这样发送本地通知:
func sendNotification(title: String, subtitle: String, body: String, timeInterval: TimeInterval)
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests(completionHandler: pendingNotificationRequests in
//Use the main thread since we want to access UIApplication.shared.applicationIconBadgeNumber
DispatchQueue.main.sync
//Create the new content
let content = UNMutableNotificationContent()
content.title = title
content.subtitle = subtitle
content.body = body
//Let's store the firing date of this notification in content.userInfo
let firingDate = Date().timeIntervalSince1970 + timeInterval
content.userInfo = ["timeInterval": firingDate]
//get the count of pending notification that will be fired earlier than this one
let earlierNotificationsCount: Int = pendingNotificationRequests.filter request in
let userInfo = request.content.userInfo
if let time = userInfo["timeInterval"] as? Double
if time < firingDate
return true
else
//Here we update the notofication that have been created earlier, BUT have a later firing date
let newContent: UNMutableNotificationContent = request.content.mutableCopy() as! UNMutableNotificationContent
newContent.badge = (Int(truncating: request.content.badge ?? 0) + 1) as NSNumber
let newRequest: UNNotificationRequest =
UNNotificationRequest(identifier: request.identifier,
content: newContent,
trigger: request.trigger)
center.add(newRequest, withCompletionHandler: (error) in
// Handle error
)
return false
return false
.count
//Set the badge
content.badge = NSNumber(integerLiteral: UIApplication.shared.applicationIconBadgeNumber + earlierNotificationsCount + 1)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval,
repeats: false)
let requestIdentifier = UUID().uuidString //You probably want to save these request identifiers if you want to remove the corresponding notifications later
let request = UNNotificationRequest(identifier: requestIdentifier,
content: content, trigger: trigger)
center.add(request, withCompletionHandler: (error) in
// Handle error
)
)
(您可能需要保存请求的标识符(如果您想更新它们,可以保存在用户默认值或核心数据中,甚至可以通过removePendingNotificationRequests(withIdentifiers:)
取消它们)
你可以像这样调用上面的函数:
sendNotification(title: "Meeting Reminder",
subtitle: "Staff Meeting in 20 minutes",
body: "Don't forget to bring coffee.",
timeInterval: 10)
将您的视图控制器声明为UNUserNotificationCenterDelegate
:
class ViewController: UIViewController, UNUserNotificationCenterDelegate
override func viewDidLoad()
super.viewDidLoad()
UNUserNotificationCenter.current().delegate = self
//...
为了处理与通知的交互,更新应用程序的徽章和即将到来的通知的徽章:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
//UI updates are done in the main thread
DispatchQueue.main.async
UIApplication.shared.applicationIconBadgeNumber -= 1
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests(completionHandler: requests in
//Update only the notifications that have userInfo["timeInterval"] set
let newRequests: [UNNotificationRequest] =
requests
.filter rq in
return rq.content.userInfo["timeInterval"] is Double?
.map request in
let newContent: UNMutableNotificationContent = request.content.mutableCopy() as! UNMutableNotificationContent
newContent.badge = (Int(truncating: request.content.badge ?? 0) - 1) as NSNumber
let newRequest: UNNotificationRequest =
UNNotificationRequest(identifier: request.identifier,
content: newContent,
trigger: request.trigger)
return newRequest
newRequests.forEach center.add($0, withCompletionHandler: (error) in
// Handle error
)
)
completionHandler()
当通知被点击时,这会通过减少它来更新应用程序徽章。此外,它还会更新待处理通知的内容标记。添加具有相同标识符的通知请求只会更新待处理的通知。
要在前台接收通知,并在通知未交互时增加应用徽章图标,请实现此:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
DispatchQueue.main.async
UIApplication.shared.applicationIconBadgeNumber += 1
completionHandler([.alert, .sound])
这里有一些 gif:
1st:接收本地通知会增加应用徽章。而与通知交互会减少应用徽章。
2nd:当应用被杀死时接收本地通知(我在此使用了 15s 的触发时间间隔)。
3rd:在前台接收通知会增加应用程序徽章,除非用户与之交互。
我的测试项目中使用的完整类如下所示:
import UIKit
import UserNotifications
class ViewController: UIViewController, UNUserNotificationCenterDelegate
var bit = true
@IBAction func send(_ sender: UIButton)
let time: TimeInterval = bit ? 8 : 4
bit.toggle()
sendNotification(title: "Meeting Reminder",
subtitle: "Staff Meeting in 20 minutes",
body: "Don't forget to bring coffee.",
timeInterval: time)
override func viewDidLoad()
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
UNUserNotificationCenter.current().delegate = self
func sendNotification(title: String, subtitle: String, body: String, timeInterval: TimeInterval)
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests(completionHandler: pendingNotificationRequests in
DispatchQueue.main.sync
let content = UNMutableNotificationContent()
content.title = title
content.subtitle = subtitle
content.body = body
let firingDate = Date().timeIntervalSince1970 + timeInterval
content.userInfo = ["timeInterval": firingDate]
let earlierNotificationsCount: Int = pendingNotificationRequests.filter request in
let userInfo = request.content.userInfo
if let time = userInfo["timeInterval"] as? Double
if time < firingDate
return true
else
let newContent: UNMutableNotificationContent = request.content.mutableCopy() as! UNMutableNotificationContent
newContent.badge = (Int(truncating: request.content.badge ?? 0) + 1) as NSNumber
let newRequest: UNNotificationRequest =
UNNotificationRequest(identifier: request.identifier,
content: newContent,
trigger: request.trigger)
center.add(newRequest, withCompletionHandler: (error) in
// Handle error
)
return false
return false
.count
content.badge = NSNumber(integerLiteral: UIApplication.shared.applicationIconBadgeNumber + earlierNotificationsCount + 1)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval,
repeats: false)
let requestIdentifier = UUID().uuidString //You probably want to save these request identifiers if you want to remove the corresponding notifications later
let request = UNNotificationRequest(identifier: requestIdentifier,
content: content, trigger: trigger)
center.add(request, withCompletionHandler: (error) in
// Handle error
)
)
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
DispatchQueue.main.async
UIApplication.shared.applicationIconBadgeNumber += 1
completionHandler([.alert, .sound])
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
DispatchQueue.main.async
UIApplication.shared.applicationIconBadgeNumber -= 1
let center = UNUserNotificationCenter.current()
center.getPendingNotificationRequests(completionHandler: requests in
let newRequests: [UNNotificationRequest] =
requests
.filter rq in
return rq.content.userInfo["timeInterval"] is Double?
.map request in
let newContent: UNMutableNotificationContent = request.content.mutableCopy() as! UNMutableNotificationContent
newContent.badge = (Int(truncating: request.content.badge ?? 0) - 1) as NSNumber
let newRequest: UNNotificationRequest =
UNNotificationRequest(identifier: request.identifier,
content: newContent,
trigger: request.trigger)
return newRequest
newRequests.forEach center.add($0, withCompletionHandler: (error) in
// Handle error
)
)
completionHandler()
【讨论】:
修复后,我删除了我的反对票并赞成这个答案。但这是一个简单需求的复杂解决方案。它不适用于具有“位置”触发器的通知。答案只适用于带有“时间”触发器的通知。确保你看到这个 OTHER chatroom discussion。主要讨论并没有发生在 Samuel 链接的聊天室中...... @Honey 感谢您帮助改进答案??【参考方案2】:我假设这都是本地通知。
AFAIK 可以解决您的问题!
当通知到达时,你要么在前台,要么在后台。
前景:您收到了userNotificationCenter(_:willPresent:withCompletionHandler:)
回调,但我认为在这种情况下您不会想要增加徽章,对吧?因为用户刚刚看到它。虽然我可以想象你可能需要在哪里这样做。假设您的应用程序类似于 WhatsApp,并且用户打开了该应用程序并向他的母亲发送了一条消息。然后他父亲的消息传来。此时他尚未打开他和他父亲之间的消息,但他看到通知。在您的遗嘱中,您可以查询getDeliveredNotifications
并调整您的徽章数量。
背景:对于iOS10+版本的本地通知,你运气不好!因为没有回调给你。通知被传递到操作系统,就是这样!曾经有一个名为 application:didReceiveLocalNotification:
的名称,但已不推荐使用。有关更多信息,请参阅here
当用户点击(前台或后台)时,您将获得userNotificationCenter(_:didReceive:withCompletionHandler:)
,但这又没有用了,因为用户已经确认收到通知并在这种情况下增加徽章不会没道理。
长话短说 AFAIK 对于本地通知,您无能为力。
如果是远程通知,那么您可以在application(_:didReceiveRemoteNotification:fetchCompletionHandler:)
中查询已发送的通知并增加徽章数量...
编辑:
由于badgeCount 已附加到到达通知中,那么如果您可以在到达之前更新它的badgeCount,那么您就万事大吉了。例如在中午 12 点,您可以随时查询pendingNotifications 列表。它将为您提供下午 12 点之后到达的所有通知,并在必要时更新它们的 badgeCount,例如如果读取了一些传递的通知,则减少他们的 badgeCount。有关此问题的完整解决方案,请参阅Carspen90's answer。他的答案的要点是
对于您要发送的任何新通知:
-
获取
pendingNotifications
过滤其触发日期早于新发送通知的通知并获取其count
将新通知的标记设置为应用的badgeCount + <strong>filtered</strong>Count + 1
if
任何待处理通知的触发日期都大于我们刚刚添加的新通知,然后我们会将 待处理 通知上的 badgeCount 增加 1
。
很明显,每当您与传递的通知交互时,您必须再次获取所有pendingNotifications
并将它们的badgeCount 减少1
警告:
对于触发基于位置的通知,您不能这样做,因为显然他们不关心时间。
【讨论】:
本地通知。你能给我一个代码表示你的答案吗 不管代码你明白我说的吗?最终我要说的是,如果你在后台,那么操作系统不会给你一个回调来传递本地通知。因此,您几乎不走运。除非您想为我给出的父亲/母亲通知示例增加徽章。但我也不建议这样做,因为当应用程序处于后台时,您的徽章计数将不准确。这会使用户感到困惑。至少据我所知,没有解决方案或破解方法。以上是关于Usernotification 框架徽章不增加的主要内容,如果未能解决你的问题,请参考以下文章