检测未确认的 UILocalNotifications
Posted
技术标签:
【中文标题】检测未确认的 UILocalNotifications【英文标题】:detect unacknowledged UILocalNotifications 【发布时间】:2013-05-09 19:35:07 【问题描述】:好像
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
和
didReceiveLocalNotification:(UILocalNotification *)notification
仅在用户确认 UILocalNotification 时触发,例如通过滑动滑块或触摸 ios 通知下拉菜单中的条目。
如果用户忽略 UILocalNotification 并通过简单地单击应用图标重新进入应用,是否有任何方法可以判断 UILocalNotification 已关闭?
我应该提到,这实际上只适用于重复通知,因为可以通过观察总数来检测非重复通知的触发。也就是说,当他们开火时,[[UIApplication sharedApplication] scheduledLocalNotifications]
的消失。
我正在寻找类似的东西..
[[UIApplication sharedApplication] unacknowledgedLocalNotifications]
唉,我找不到类似的东西。
【问题讨论】:
如果您的通知在scheduledLocalNotifications
中不,则不再安排它,因此它一定已经触发了。
'刚刚编辑了问题。我实际上有那个文本,但我想尽可能简单(即更少的文本)。
我感觉您想要的东西并不存在,但这会向 Apple 的错误报告者提出很棒的 功能请求。
谢谢 :) 遗憾的是,我向 Apple 提交了一些“很棒的功能创意”,但总是被忽略。
我也是,但我仍然这样做!我坚持下去:即使他们说我错了,我也会继续追随他们。
【参考方案1】:
好吧,您可以在[[UIApplication sharedApplication] scheduledLocalNotifications]
中查看您的预定通知。要了解计划的重复通知是否已触发,请访问 fireDate
属性以查看为通知设置的初始日期。然后检查repeatInterval
属性。
所以你有两个变量,一个是初始的NSDate
,比如说2013-05-08 12:00
,第二个是重复间隔,比如说每天。通过执行[NSDate date]
,您将获得我所在的当前日期(在瑞典)现在是2013-05-09 22:45
。所以这意味着有一个通知用户没有采取行动。
因此,您需要创建一个方法来接受这些参数,然后从初始日期开始迭代,以查看在当前日期时间之前错过了多少通知。
你会发现NSCalendar
s dateByAddingComponents:toDate:options很有用。
【讨论】:
说实话,我正在实施这个,并认为 Apple必须 处理好这个以节省我一堆代码。谢谢! 我也是,不幸的是你必须自己实现它。这是一项小工作,但效果很好。 您有什么理由使用 NSCalendars 和 Components 而不仅仅是 NSDate 的 timeIntervalSinceNow?这样你就可以像for (UILocalNotification *uiln in [[UIApplication sharedApplication] scheduledLocalNotifications]) if ([uiln.fireDate timeIntervalSinceNow] < 0) // do some stuff
@arigold 因为 fireDate 属性是静态的,因此它不会在每次重复后动态变化。
@PeterWarbo 如果没有重复间隔怎么办...所以 uiln 在数组中不可用...那我如何获得该 uiln?【参考方案2】:
此后每个人都可能继续前进,但我想分享我对这个问题的解决方案。 (抱歉,变量名太长了……)
这个想法很简单:永远保留 fireDate 的未来。
-每次调用 didFinishLaunchingWithOptions 或 didReceiveLocalNotification 时,只需取消您当前的通知并在未来重新安排一个具有 fireDate 间隔单位的新通知
-当你的应用程序启动时迭代所有计划的通知,如果 fireDate 不在未来,你就知道它被忽略了
就我而言,通知每周重复一次。我首先在 didFinishLaunchingWithOptions 中重新安排任何确认的通知:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
UILocalNotification* localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif != nil)
[NotificationsHelper rescheduleNotification:localNotif];
还有在 didReceiveLocalNotification 中:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *) notification
[NotificationsHelper rescheduleNotification:notification];
在应用启动时,我会检查所有通知中是否有任何过去有 fireDate 的通知:
- (void)applicationDidBecomeActive:(UIApplication *)application
[self checkLocalNotifications:application];
我的“checkLocalNotifications”函数的代码:
- (void) checkLocalNotifications:(UIApplication *) application
UIApplication* app = [UIApplication sharedApplication];
NSArray* eventArray = [app scheduledLocalNotifications];
for (int i = 0; i < [eventArray count]; i++)
UILocalNotification* notification = [eventArray objectAtIndex:i];
if ([NotificationsHelper wasWeeklyRepeatingNotificationIgnored:notification])
[NotificationsHelper rescheduleNotification:notification];
NSLog(@"NotificationWasIgnored: %@ %@",notification.alertAction, notification.alertBody );
我的“wasWeeklyRepeatingNotificationIgnored”函数的代码:
+ (BOOL) wasWeeklyRepeatingNotificationIgnored:(UILocalNotification*) the_notification
BOOL result;
NSDate* now = [NSDate date];
// FireDate is earlier than now
if ([the_notification.fireDate compare:now] == NSOrderedAscending)
result = TRUE;
else
result = FALSE;
return result;
我的“rescheduleNotification”函数代码:
+ (void) rescheduleNotification:(UILocalNotification*) the_notification
UILocalNotification* new_notification = [[UILocalNotification alloc] init];
NSMutableDictionary* userinfo = [[NSMutableDictionary alloc] init];
[new_notification setUserInfo:userinfo];
[new_notification setRepeatInterval:the_notification.repeatInterval];
[new_notification setSoundName:UILocalNotificationDefaultSoundName];
[new_notification setTimeZone:[NSTimeZone defaultTimeZone]];
[new_notification setAlertAction:the_notification.alertAction];
[new_notification setAlertBody:the_notification.alertBody];
[new_notification setRepeatCalendar:[NSCalendar currentCalendar]];
[new_notification setApplicationIconBadgeNumber:the_notification.applicationIconBadgeNumber];
NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* weekdayComponents = [gregorian components:NSWeekdayCalendarUnit
fromDate:the_notification.fireDate];
NSInteger weekday = [weekdayComponents weekday];
NSDate* next_week = [self addDay:weekday toHourMinute:the_notification.fireDate];
[new_notification setFireDate:next_week];
[[UIApplication sharedApplication] scheduleLocalNotification:new_notification];
[[UIApplication sharedApplication] cancelLocalNotification:the_notification];
【讨论】:
同样,这仅适用于重复的 UILN,否则系统中将不存在 UILN。也就是说,iOS 会删除触发的非重复 UILN。 顺便说一句,永远不要为长变量名道歉。恕我直言,最好过分描述你的名字的描述性。还有漂亮的代码。【参考方案3】:如果您的 UILocalNotifications 增加了应用程序图标徽章编号(即应用程序图标右上角红色圆圈中的数字),那么会有一个 简单得离谱检查未确认的 UILocalNotifications 的方法:只需检查当前的 applicationIconBadgeNumber
是什么:
- (void)applicationWillEnterForeground:(UIApplication *)application
int unacknowledgedNotifs = application.applicationIconBadgeNumber;
NSLog(@"I got %d unacknowledged notifications", unacknowledgedNotifs);
//do something about it...
//You might want to reset the count afterwards:
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
【讨论】:
如果用户从托盘中关闭通知,徽章不会改变。以上是关于检测未确认的 UILocalNotifications的主要内容,如果未能解决你的问题,请参考以下文章
如何检测和删除(在会话期间)不能被垃圾收集的未使用的 @ViewScoped bean