How to schedule a notification that will repeat with some frequency after specific time passes

540 Views Asked by At

I don't see support for scheduling such kind of notification i.e. that repeats only when a specific time passes. The problem is that the schedule fires immediately without waiting for the exact time although repeats correctly.

e.g. here is the code for scheduling a repeating notification after 10 minutes. This doesn't wait for the 10 minutes - fires immediately in the next minute from now.

NSDate *theDate = [NSDate dateWithTimeIntervalSinceNow:60*10];
NSDateComponents *dateForSchedule = [[[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian] components:NSCalendarUnitMinute|NSCalendarUnitHour|NSCalendarUnitDay|NSCalendarUnitWeekday|NSCalendarUnitMonth|NSCalendarUnitYear fromDate:theDate];
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.body = "Your notification is here.";
content.sound = [UNNotificationSound defaultSound];
content.categoryIdentifier = CALL_NOTIFICATION_CATEGORY;

NSDateComponents* date = [[NSDateComponents alloc] init];

if ([self.selectedFrequecy isEqualToString:HOURLY]) {
    date.minute = dateForSchedule.minute;
} else if ([self.selectedFrequecy isEqualToString:DAILY]) {
    date.hour = dateForSchedule.hour;
    date.minute = dateForSchedule.minute;
} else if ([self.selectedFrequecy isEqualToString:WEEKLY]) {
    date.weekday = dateForSchedule.weekday;
    date.hour = dateForSchedule.hour;
    date.minute = dateForSchedule.minute
} else if ([self.selectedFrequecy isEqualToString:MONTHLY]) {
    date.day = dateForSchedule.day;
    date.hour = dateForSchedule.hour;
    date.minute = dateForSchedule.minute;
} else if ([self.selectedFrequecy isEqualToString:YEARLY] || [self.selectedFrequecy isEqualToString:ONCE]) {
    date.month = dateForSchedule.month;
    date.day = dateForSchedule.day;
    date.hour = dateForSchedule.hour;
    date.minute = dateForSchedule.minute;
}

UNCalendarNotificationTrigger* trigger;

if ([_selectedFrequecy isEqualToString:ONCE]) {
    trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:date repeats:NO];
} else {
    trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:date repeats:YES];
}

// Create the request object.
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:self.callSchedule.id content:content trigger:trigger];

[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error)
 {
     if (error != nil) {
         NSLog(@"%@", error.localizedDescription)
     }
 }];

here is another block of code for a repeating notification that will fire daily after 3 days.

NSDate *theDate = [NSDate dateWithTimeIntervalSinceNow:60*60*24*3];
NSDateComponents *dateForSchedule = [[[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian] components:NSCalendarUnitMinute|NSCalendarUnitHour|NSCalendarUnitDay|NSCalendarUnitWeekday|NSCalendarUnitMonth|NSCalendarUnitYear fromDate:theDate];
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.body = "Your notification is here.";
content.sound = [UNNotificationSound defaultSound];
content.categoryIdentifier = CALL_NOTIFICATION_CATEGORY;

NSDateComponents* date = [[NSDateComponents alloc] init];

if ([self.selectedFrequecy isEqualToString:HOURLY]) {
    date.minute = dateForSchedule.minute;
} else if ([self.selectedFrequecy isEqualToString:DAILY]) {
    date.hour = dateForSchedule.hour;
    date.minute = dateForSchedule.minute;
} else if ([self.selectedFrequecy isEqualToString:WEEKLY]) {
    date.weekday = dateForSchedule.weekday;
    date.hour = dateForSchedule.hour;
    date.minute = dateForSchedule.minute
} else if ([self.selectedFrequecy isEqualToString:MONTHLY]) {
    date.day = dateForSchedule.day;
    date.hour = dateForSchedule.hour;
    date.minute = dateForSchedule.minute;
} else if ([self.selectedFrequecy isEqualToString:YEARLY] || [self.selectedFrequecy isEqualToString:ONCE]) {
    date.month = dateForSchedule.month;
    date.day = dateForSchedule.day;
    date.hour = dateForSchedule.hour;
    date.minute = dateForSchedule.minute;
}

UNCalendarNotificationTrigger* trigger;

if ([_selectedFrequecy isEqualToString:ONCE]) {
    trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:date repeats:NO];
} else {
    trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:date repeats:YES];
}

// Create the request object.
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:self.callSchedule.id content:content trigger:trigger];

[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error)
 {
     if (error != nil) {
         NSLog(@"%@", error.localizedDescription)
     }
 }];

This also doesn't wait for the 3 days but fires immediately on the next day.

The main problem in both is that it ignores the time till which it should wait to start firing the notification. If anybody has understood the problem, will you take some time to figure out what's wrong or if it's possible. I will be really thankful.

1

There are 1 best solutions below

2
On

In AppDelegate take permission didfinishlauchingwithoption

if( SYSTEM_VERSION_LESS_THAN( @"10.0" ) )
{

    [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound |    UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
    [[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error)
     {
         if( !error )
         {
             [[UIApplication sharedApplication] registerForRemoteNotifications];  // required to get the app to do anything at all about push notifications
             NSLog( @"Push registration success." );
         }
         else
         {
             NSLog( @"Push registration FAILED" );
             NSLog( @"ERROR: %@ - %@", error.localizedFailureReason, error.localizedDescription );
             NSLog( @"SUGGESTIONS: %@ - %@", error.localizedRecoveryOptions, error.localizedRecoverySuggestion );  
         }  
     }];  
}

In ViewController- Implement delegate here -

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    NSDate *theDate = [NSDate dateWithTimeIntervalSinceNow:60*1];
    NSDateComponents *dateForSchedule = [[[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian] components:NSCalendarUnitMinute|NSCalendarUnitHour|NSCalendarUnitDay|NSCalendarUnitWeekday|NSCalendarUnitMonth|NSCalendarUnitYear fromDate:theDate];
    UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
    content.body = @"Your notification is here.";
    content.sound = [UNNotificationSound defaultSound];
    content.categoryIdentifier = CALL_NOTIFICATION_CATEGORY;

    NSDateComponents* date = [[NSDateComponents alloc] init];
    date.month = dateForSchedule.month;
    date.day = dateForSchedule.day;
    date.hour = dateForSchedule.hour;
    date.minute = dateForSchedule.minute;

    UNCalendarNotificationTrigger* trigger;
    trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:date repeats:NO];

    UNUserNotificationCenter *centre = [UNUserNotificationCenter currentNotificationCenter];
    centre.delegate = self;
    // Create the request object.
    UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:self.callSchedule.id content:content trigger:trigger];

    [centre addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error)
     {
         if (error != nil) {
             NSLog(@"%@", error.localizedDescription);
         }
     }];
}

-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{

    //Called when a notification is delivered to a foreground app.

    NSLog(@"Userinfo %@",notification.request.content.userInfo);

    completionHandler(UNNotificationPresentationOptionAlert);
}

-(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler{

    //Called to let your app know which action was selected by the user for a given notification.

    NSLog(@"Userinfo %@",response.notification.request.content.userInfo);

}

I am able to get the notification at correct time. I have taken all code from your code snippet with very small change just to run the code. You can see if you find anything different.

Hope this suggestion helps you !