检测未确认的 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。所以这意味着有一个通知用户没有采取行动。

因此,您需要创建一个方法来接受这些参数,然后从初始日期开始迭代,以查看在当前日期时间之前错过了多少通知。

你会发现NSCalendars 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的主要内容,如果未能解决你的问题,请参考以下文章

testflight 未检测到此应用的应用令牌

如何检测和删除(在会话期间)不能被垃圾收集的未使用的 @ViewScoped bean

B2B网页付款时,出现“对不起,未检测到签名控件”,不能正常支付

Android 跌倒检测问题

xmpp ejabberd:对许多未确认的节

Firebase 确认电子邮件未发送