detect unacknowledged UILocalNotifications

爱⌒轻易说出口 提交于 2019-12-07 04:01:22

问题


It seems that

didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

and

didReceiveLocalNotification:(UILocalNotification *)notification

are only triggered if the user acknowledges the UILocalNotification, for example by swiping the slider or touching the entry in iOS's Notification pull-down.

Is there any way to tell that a UILocalNotification has gone off if the user ignores the UILocalNotification and re-enters the app by simply clicking on the app icon?

I should mention that this really only applies to repeating notifications because the firing of non-repeating notifications can be detected by observing the total count. That is, when they fire, the vanish from [[UIApplication sharedApplication] scheduledLocalNotifications].

I'm looking for something like..

[[UIApplication sharedApplication] unacknowledgedLocalNotifications]

Alas, I can't find anything like it.


回答1:


Well, you can check your scheduled notifications inside [[UIApplication sharedApplication] scheduledLocalNotifications]. To find out if a scheduled repeating notification has fired access the fireDate property to see what was the initial date set for the notification. Then check the repeatInterval property.

So there you have 2 variables, one is the initial NSDate, lets say 2013-05-08 12:00 and second is the repeat interval, lets say daily. And by doing a [NSDate date] you will get the current date which where I'm located (in Sweden) is now 2013-05-09 22:45. So this means that there is one notification the user has not acted on.

So you will need to create a method that will take these arguments and then iterate from the initial date to see how many notifications that have been missed until the current datetime.

You will find NSCalendars dateByAddingComponents:toDate:options useful.




回答2:


Everyone has likely since moved on, but I'd like to share my solution to this problem. (Sorry about the long variables names...)

The idea is simple: always keep the fireDate in the future.

-every time didFinishLaunchingWithOptions or didReceiveLocalNotification is invoked, simply cancel your current notification and reschedule a new one with a fireDate one interval unit in the future

-When your app launches iterate through all scheduled notifications, if the fireDate is not in the future you know that it was ignored

In my case, the notifications have a weekly repeat interval. I first reschedule any acknowledged notifications in didFinishLaunchingWithOptions:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UILocalNotification* localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];

    if (localNotif != nil)
    {
        [NotificationsHelper rescheduleNotification:localNotif];
    }
}

And also in didReceiveLocalNotification:

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *) notification
{
   [NotificationsHelper rescheduleNotification:notification];
}  

At App Launch I check all notifications for any with a fireDate in the past:

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [self checkLocalNotifications:application];
}

Code for my "checkLocalNotifications" function:

- (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 );
        }
    }
}

Code for my "wasWeeklyRepeatingNotificationIgnored" function:

+ (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;
}

Code for my "rescheduleNotification" function:

+ (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];
}



回答3:


If your UILocalNotifications increment the application icon badge number (i.e. the number in the red circle on the top right of the app's icon), then there is a ridiculously simple way to check for unacknowledged UILocalNotifications: just check what the current applicationIconBadgeNumber is:

- (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];

}


来源:https://stackoverflow.com/questions/16469721/detect-unacknowledged-uilocalnotifications

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!