这个问题是关于 iOS 10 中新的
UserNotifications
框架。
我有一个应用程序,在用户在应用程序中执行特定操作后每半小时安排一次本地通知,从 1 小时开始。
为了避免用户的锁定屏幕或通知中心混乱,我只想一次显示一个通知,因此只有一个通知包含最新的相关信息。我的计划是在每次出现新通知时清除所有已发送的通知。
看起来这应该可以通过
willPresent
的新 UNUserNotificationCenterDelegate
方法实现,但它的行为并不像我预期的那样。
我调用以下函数来设置所有通知,从应用程序中事件发生后 1 小时开始,每半小时安排一次通知,直到事件发生后 23.5 小时发出最后一个通知:
func updateNotifications() {
for hour in 1...23 {
scheduleNotification(withOffsetInHours: Double(hour))
scheduleNotification(withOffsetInHours: Double(hour) + 0.5)
}
}
这是实际根据
mostRecentEventDate
安排通知的函数,这是在其他地方设置的 Date
:
func scheduleNotification(withOffsetInHours: Double) {
// set up a Date for when the notification should fire
let offsetInSeconds = 60 * 60 * withOffsetInHours
let offsetFireDate = mostRecentEventDate.addingTimeInterval(offsetInSeconds)
// set up the content of the notification
let content = UNMutableNotificationContent()
content.categoryIdentifier = "reminder"
content.sound = UNNotificationSound.default()
content.title = "Attention!"
content.body = "It has been \(withOffsetInHours) hours since the most recent event."
// set up the trigger
let triggerDateComponents = Calendar.current.components([.year, .month, .day, .hour, .minute, .second], from: offsetFireDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDateComponents, repeats: false)
// set up the request
let identifier = "reminder\(withOffsetInHours)"
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
// add the request for this notification
UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in
if error != nil {
print(error)
}
})
}
在我的
UNUserNotificationCenterDelegate
中,我的 willPresent
方法设置如下:
func userNotificationCenter(_: UNUserNotificationCenter, willPresent: UNNotification, withCompletionHandler: (UNNotificationPresentationOptions) -> Void) {
print("will present...")
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
withCompletionHandler([.alert,.sound])
}
我知道正在调用
willPresent
函数,因为它打印“将呈现...”,但通知中心中的现有通知不会被清除。有谁知道为什么这不起作用?或者是否有办法让它按照我想要的方式工作?
编辑:我想出了另一种方法来实现同样的目标,但它似乎也不起作用。
我的想法是使用
willPresent
使传入的预定通知静音,同时安排另一个通知立即到达(无需触发)。所有计划立即到达的通知都具有相同的标识符,因此应始终替换具有该标识符的现有通知,就像 this 2016 WWDC talk 中关于新 UserNotifications 框架的 20:00 左右的示例一样。这是我更新的willPresent
方法:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent: UNNotification, withCompletionHandler: (UNNotificationPresentationOptions) -> Void) {
let identifier = willPresent.request.identifier
if identifier != "reminder" {
let offsetInHoursString = identifier.replacingOccurrences(of: "reminder", with: "")
let content = UNMutableNotificationContent()
content.categoryIdentifier = "reminder"
content.sound = UNNotificationSound.default()
content.title = "Attention!"
content.body = "It has been \(offsetInHoursString) hours since the most recent event."
let identifier = "hydrationReminder"
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: nil)
center.add(request, withCompletionHandler: { (error) in
if error != nil {
print(error)
}
})
withCompletionHandler([])
} else {
withCompletionHandler([.alert,.sound])
}
}
编辑:我终于意识到,
willPresent
只会在应用程序位于前台时被调用,正如它在此页面顶部所说的那样,所以这些方法实际上都不应该起作用。我以为每次收到通知都会调用willPresent
。回到绘图板这个“仅最新、最相关的通知”的想法......随着 iOS 12 中分组通知的引入,更新旧通知(以减少通知混乱为目标)似乎不再那么重要。我仍然希望能够做到这一点,以尽量减少混乱的出现,而且远程推送通知(可以在事后更新)和本地通知(以后不能更新)之间似乎应该具有功能对等性。然而,由于苹果引入了分组通知,我预计他们不太可能实现更新旧本地通知的功能,而是让应用程序只发送新通知并将它们与现有通知分组在一起。
iOS 10 允许更新通知。您只需要做的就是——保持通知具有相同的
标识符。 让我们看一下演示:
第一个通知:
NSURL * imageUrl = [[NSBundle mainBundle] URLForResource:@"dog" withExtension:@"png"];
UNNotificationAttachment *imgAtt = [UNNotificationAttachment attachmentWithIdentifier:@"image" URL:imageUrl options:nil error:&error];
NSURL * mp4Url = [[NSBundle mainBundle] URLForResource:@"media" withExtension:@"mp4"];
UNNotificationAttachment *mediaAtt = [UNNotificationAttachment attachmentWithIdentifier:@"image" URL:mp4Url options:nil error:&error];
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc]init];
//在通知中心显示的总是第一个多媒体资源
content.attachments = @[imgAtt,mediaAtt];
content.badge = @1;
content.title = @"Wake Up";
content.subtitle = @"First time";
content.body = @"next time。。。 ";
content.categoryIdentifier = @"wakeup";
content.launchImageName = @"dog";
content.sound = [UNNotificationSound defaultSound];
// content.threadIdentifier = @"";
content.userInfo = @{@"first":@"5:00 am",@"second":@"6:00"};
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5.0 repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"com.junglesong.pushtestdemo.wakeup" content:content trigger:trigger];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
NSLog(@"wake up message has been deliverd!");
}];
更新第一个通知:
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc]init];
content.badge = @1;
content.title = @"Update!dear,wake up";
content.subtitle = @"Update! dear,please";
content.body = @"Update!shall we have breakfast?";
content.categoryIdentifier = @"wakeup";
content.launchImageName = @"dog";
content.sound = [UNNotificationSound defaultSound];
// content.threadIdentifier = @"";
content.userInfo = @{@"first":@"5:00 am",@"second":@"6:00"};
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:5.0 repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:@"com.junglesong.pushtestdemo.wakeup" content:content trigger:trigger];
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
NSLog(@"wake up message has been updated!");
}];
现在,你添加了两个通知。但是系统将它们视为相同。所以只有一个。第二个通知取代了第一个。在 iOS 10 中,称之为
update。 “identifier”属性是UNNotificationRequest的id,可以区分通知。
将所有标识符存储在数组中,然后使用 removeDeliveredNotifications(withIdentifiers:)
控制它们