I have searched a lot to try to find a specific solution to this problem. I have an app that uses the former UILocalNotification system to send local notifications, and this still works fine under iOS 10.3.3. However, I have tried to convert this to the new UNNotification system because the former system is deprecated. No matter whether I try a UNCalendarNotificationTrigger or a UNTimeIntervalNotificationTrigger, the delegate does not receive a call. Here is the code for the triggering viewcontroller.
if (isItTime){
NSCalendar *currentCalendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
[currentCalendar setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents *components = [currentCalendar components:NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitTimeZone fromDate:[now dateByAddingTimeInterval:30]];
// components.second = 0;
NSLog(#"trigger components: %#", components);
UNCalendarNotificationTrigger* trigger = [UNCalendarNotificationTrigger
triggerWithDateMatchingComponents:components repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:#"invite" content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Something went wrong: %#",error);
}
}];
[self.currentLocalNotificationRequests addObject:request];
return request;
}else{
return nil;
}
And here is the code for the delegate (appdelegate) didFinishLaunching:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
// Enable or disable features based on authorization.
NSLog(#"_prefix:set($class $method $line)");
NSUserDefaults *storage = [NSUserDefaults standardUserDefaults];
if(granted == YES){
[storage setBool:YES forKey:#"permission granted"];
[storage setBool:YES forKey:#"alert permission granted"];
[storage setBool:YES forKey:#"sound permission granted"];
}else{
NSLog(#"No permission granted");
[storage setBool:NO forKey:#"permission granted"];
};
}];
Code for the appdelegate to get the notifications:
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler{
NSLog(#"appdelegate - center didReceiveNotificationResponse");
NSString *actionIdentifier = response.actionIdentifier;
UNNotification *notification = response.notification;
if([actionIdentifier isEqual:#"com.apple.UNNotificationDefaultActionIdentifier"] || [actionIdentifier isEqual:#"com.apple.UNNotificationDismissActionIdentifier"]){
}else{
BOOL accept = [actionIdentifier isEqual:#"ACCEPT_IDENTIFIER"];
BOOL stop = [actionIdentifier isEqual:#"DECLINE_IDENTIFIER"];
BOOL doNotDisturb = [actionIdentifier isEqual:#"DO_NOT_DISTURB_IDENTIFIER"];
if (accept){NSLog(#"accept");
[self handleAcceptActionWithNotification:notification];
}
else if (stop){NSLog(#"stop");
[self handleDeclineActionWithNotification:notification];
}
else if(doNotDisturb) {NSLog(#"do not disturb");
[self handleDoNotDisturbActionWithNotification:notification];
};
}
completionHandler();
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
NSLog(#"appdelegate willPresentNotification");
UNNotificationRequest * request = notification.request;
NSString * actionIdentifier = request.identifier;
if([actionIdentifier isEqualToString:UNNotificationDismissActionIdentifier] || [actionIdentifier isEqualToString:UNNotificationDefaultActionIdentifier]){
}else{
if([actionIdentifier isEqualToString:#"invite"]){
NSLog(#"app delegate notification received while in foreground");
}
}
completionHandler(UNNotificationPresentationOptionAlert + UNNotificationPresentationOptionSound);
}
Here is the NSLog of the triggering code:
<NSDateComponents: 0x146d51c0>
TimeZone: America/Chicago (CDT) offset -18000 (Daylight)
Calendar Year: 2017
Month: 10
Leap month: no
Day: 29
Hour: 14
Minute: 3
Second: 4
It is very clear that appdelegate methods are not being called by the system (I did put the app in background before the notification time, so the didReceiveNotification method should have been called.
If anyone can help, I would appreciate it!
Also, this code in viewDidLoad:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveNotificationFromAppDelegate:)
name:kAppDelegateNotification
object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(applicationBecameActive) name:UIApplicationDidBecomeActiveNotification object:nil];
self.currentLocalNotificationRequests = [[NSMutableArray alloc]init];
/*
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(checkDndIndicator) name:UIApplicationDidBecomeActiveNotification object:nil];
*/
UNNotificationAction *acceptAction = [UNNotificationAction actionWithIdentifier:#"ACCEPT_IDENTIFIER" title:NSLocalizedString(#"Continue notifications", nil) options:UNNotificationActionOptionAuthenticationRequired];
UNNotificationAction *declineAction = [UNNotificationAction actionWithIdentifier:#"DECLINE_IDENTIFIER" title:NSLocalizedString(#"Stop notifications", nil) options:UNNotificationActionOptionAuthenticationRequired];
UNNotificationAction *doNotDisturbAction = [UNNotificationAction actionWithIdentifier:#"DO_NOT_DISTURB_IDENTIFIER" title:NSLocalizedString(#"Start Do Not Disturb", nil) options:UNNotificationActionOptionAuthenticationRequired];
NSArray *actions = [NSArray arrayWithObjects:acceptAction, declineAction, doNotDisturbAction, nil];
// NSArray *intentIdentifiers = [NSArray arrayWithObjects:#"none", nil];
UNNotificationCategory *invite = [UNNotificationCategory categoryWithIdentifier:#"com.nelsoncapes.localNotification" actions:actions intentIdentifiers: #[] options:UNNotificationCategoryOptionNone];
NSSet *categories = [NSSet setWithObjects:invite, nil];
[center setNotificationCategories:categories];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
// Enable or disable features based on authorization.
NSLog(#"request granted");
}];
And code to start the trigger process:
-(UNNotificationRequest *)startLocalNotification:(NSDate *)fireDate :
(NSMutableDictionary *)userInfo{
NSUserDefaults *storage = [NSUserDefaults standardUserDefaults];
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
[center removeAllPendingNotificationRequests];
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = NSLocalizedString(#"TimeChime Alert", nil);
content.body = NSLocalizedString(#"Click to Stop or Change Timer",nil);
content.categoryIdentifier = #"com.nelsoncapes.localNotification";
It turns out that this problem is obscure but the fix is easy. Unfortunately, I didn't carefully follow the first rule of coding: RTFD.
Apple's documentation for UNNotificationRequest> identifier states:
"If you use the same identifier when scheduling a new notification, the system removes the previously scheduled notification with that identifier and replaces it with the new one."
My code was using the same identifier for each UNNotificationRequest. Although the calendar notification date for each request was different, the system only kept the latest-dated request. In my case, the trigger would have fired after 1 hour, and I expected it to fire after 15 minutes. This is why I never saw a notification on the device and why I never saw a breakpoint in the delegate's didReceiveNotificationResponse method.
The fix is very easy. Just supply a unique identifier in the following code. After that, the code works.
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:#"invite" content:content trigger:trigger];
Replace #"invite" with a unique identifier for each request.
I was not getting my notification because I did not specify the required date components to pass to my UNCalendarNotificationTrigger.
This does not work:
NSDateComponents *dateComponents = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour) fromDate:[[NSDate date] dateByAddingTimeInterval:5]];
This works:
NSDateComponents *dateComponents = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitNanosecond) fromDate:[[NSDate date] dateByAddingTimeInterval:5]];
Related
I have local notification setup in one of my application which remind the user regarding medication on a regular basis and n times daily depends on user selection. If the user setup the reminder in the application and changes the date on device setting, reminder not triggering for the next scheduled time. But works fine for the other scheduled times. First notification scheduled is missing. Works fine for normal scenarios. Anyone faced similar issues? TIA. Code snippet as follows:
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center setNotificationCategories:[NSSet set]];
UNAuthorizationOptions options = UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge;
[center requestAuthorizationWithOptions:options
completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!granted) {
PRLog(#"Something went wrong");
}else{
dispatch_async(dispatch_get_main_queue(), ^{
[[UIApplication sharedApplication] registerForRemoteNotifications];
});
[LocalNotificationShared registerCategories];
}
}];
}
and triggering part like:
NSDateComponents *triggerDate = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond|NSCalendarUnitTimeZone fromDate:date]; UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:triggerDate repeats:NO];
NSString *s = [NSString stringWithFormat:#"%#",#([NSDate timeIntervalSinceReferenceDate])];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:s
content:content trigger:trigger];
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
PRLog(#"Something went wrong: %#",error);
}
}];
From what I've observed, the time interval for a scheduled notification is independent of the device time. So if you schedule a notification for an hour away, and then set your device time to 59 minutes ahead, it won't matter - you will still have to wait the full hour for it to trigger.
I have a code that allows the device to run an update. It works perfectly when the ipad is not under guided access for information under iOS11 (and it worked under iOS10 & guided accesss):
- (void)viewDidLoad
{
...
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:#"Update!" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:#"Update!"
arguments:nil];
// Configure the trigger for a 7am update.
NSDateComponents* date = [[NSDateComponents alloc] init];
date.hour = 18;
date.minute = 31;
UNCalendarNotificationTrigger* trigger = [UNCalendarNotificationTrigger
triggerWithDateMatchingComponents:date repeats:NO];
// Create the request object.
UNNotificationRequest* request = [UNNotificationRequest
requestWithIdentifier:#"update" content:content trigger:trigger];
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"%#", error.localizedDescription);
}
}];
}
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
// Update the app interface directly.
NSLog(#"");
// Play a sound.
completionHandler(UNNotificationPresentationOptionSound);
}
I found that Ticket, but no exhaustive explanations to accomplish it:
Is it possible under iOS11 to launch notification on guided access?
Thanks in advance.
It appears this was nothing more than an iOS bug which has been fixed in iOS 11.2.5 beta 4. Please see my own question here for more information.
If you can wait until iOS 11.2.5 is released (which will hopefully be soon according to Apple) the issue should just resolve itself. Otherwise you'll need to investigate something like a sockets system instead.
Can u help me how to cancel local notification in iOS 10
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center removeAllPendingNotificationRequests];
[center removePendingNotificationRequestsWithIdentifiers:#[ CYLInviteCategoryIdentifier ]];
removePendingNotificationRequestsWithIdentifiers i cant understand
While creating a Local notification, you can pass an identifier to each notification. Use the same identifier to remove the local notification.
Code to create local notification:-
NSString *identifier = #"Unique Identifier";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier content:content trigger:trigger]
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Something went wrong: %#",error);
}
}];
Code to Cancel Notification:-
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
NSArray *array = [NSArray arrayWithObjects:#"Identifier1",#"Identifier2", nil];
[center removePendingNotificationRequestsWithIdentifiers:array];
Try this
[[UNUserNotificationCenter currentNotificationCenter]getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
NSLog(#"count%lu",(unsigned long)requests.count);
if (requests.count>0) {
UNNotificationRequest *pendingRequest = [requests objectAtIndex:0];
if ([pendingRequest.identifier isEqualToString:#"identifier"]) {
[[UNUserNotificationCenter currentNotificationCenter]removePendingNotificationRequestsWithIdentifiers:#[pendingRequest.identifier]];
}
}
}];
I don't use any of the above solutions. I don't cancel any single notifications. Rather, whenever the user runs the app I cancel ALL the local notifications and run the code that recreates them all with the new parameters, which will cancel any local notifications that need cancelling. Less code surface, less to test, creating notifications is generally an inexpensive operation. Many, many apps use this solution, consider whether you could use this yourself.
You can use below code to remove single local notification.
UIApplication *app = [UIApplication sharedApplication];
NSArray *allLocalNoti = [app scheduledLocalNotifications];
for (int i=0; i<[allLocalNoti count]; i++)
{
UILocalNotification* currentLocalNotification = [allLocalNoti objectAtIndex:i];
NSDictionary *userInfoCurrent = currentLocalNotification.userInfo;
NSString *uid=[NSString stringWithFormat:#"%#",[userInfoCurrent valueForKey:#"uid"]];
if ([uid isEqualToString:uidtodelete])
{
[app cancelLocalNotification:currentLocalNotification];
break;
}
}
Happy Coding...
I am using UNUsernotification for iOS 10 and Xcode 8 Beta 2
I wrote below code for Local Notification in iOS device:
-(void) localNotificationForiOS10:(NSDate *) _reminderDate{
NSLog(#"_reminderDate %#",_reminderDate);
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
[calendar setTimeZone:[NSTimeZone localTimeZone]];
NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour|NSCalendarUnitMinute|NSCalendarUnitSecond|NSCalendarUnitTimeZone fromDate:_reminderDate];
NSLog(#"NSDateComponents %#",components);
UNMutableNotificationContent *objNotificationContent = [[UNMutableNotificationContent alloc] init];
objNotificationContent.title = [NSString localizedUserNotificationStringForKey:#"Event Name!" arguments:nil];
objNotificationContent.body = [NSString localizedUserNotificationStringForKey:#"You have event reminder"
arguments:nil];
objNotificationContent.sound = [UNNotificationSound defaultSound];
/// 4. update application icon badge number
objNotificationContent.badge = #([[UIApplication sharedApplication] applicationIconBadgeNumber] + 1);
UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:components repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:#"firedate"
content:objNotificationContent trigger:trigger];
/// 3. schedule localNotification
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(#"Local Notification succeeded");
}
else {
NSLog(#"Local Notification failed");
}
}];
}
I want to set three different or multiple future dates and want reminder of event on defined dates.
When I used the above code for 3 different time on same date
e.g. (2016-12-29 18:05 ,2016-12-29 18:10, 2016-12-29 18:15) than only last one gave notification.
I register Location notification in AppDelegate file.
application.applicationIconBadgeNumber = 0;
if ([[[UIDevice currentDevice] systemVersion] floatValue] > 10.0f) {
#if XCODE_VERSION_GREATER_THAN_OR_EQUAL_TO_8
/// schedule localNotification, the delegate must be set before the application returns from applicationDidFinishLaunching:.
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
#endif
} else {
UILocalNotification *localNotifacation = [self getLocalNotificationFromLaunchOptions:launchOptions];
if (localNotifacation) {
NSString *title = localNotifacation.alertBody;
NSLog(#"Add Title %#",title);
}
}
I tried my self and I tried it.
I am able to cancel the Local Notification in iOS 10.
here is posted code.
how to cancel a local notification in iphone
I am trying to implement local notification in my application. I don't know how to do properly, below code I am using for new data arrival process, here after how to implement Notification process and I need notifications during both foreground and background modes.
Below I had successfully background fetching process for new data arrival checking method
// Value matching and trying to get new data
[live_array removeObjectsInArray:stored_array];
// if you require result as a string
NSString *result = [stored_array componentsJoinedByString:#","];
NSLog(#"New Data: %#", result); // objects as string:
Above code finally giving some string value...Once the value came I want to show the notification. Everything I am doing is in the App Delegate.
1) When the app is closed, schedule a local notification that will fire in 24 hours
- (void)applicationDidEnterBackground:(UIApplication *)application
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = [[NSDate date] dateByAddingTimeInterval:60*60*24];
notification.alertBody = #"24 hours passed since last visit :(";
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
2) if the app is opened (before the local notification fires), cancel the local notification
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
}
//For local Notification
first thing we need to do is register the notifications.
// New for iOS 8 - Register the notifications
UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
Now let’s create the notification itself
UILocalNotification *notification = [[UILocalNotification alloc] init];
if (notification)
{
notification.fireDate = _datePicker.date;
NSDate *fireTime = [[NSDate date] addTimeInterval:10]; // adds 10 secs
notification.fireDate = fireTime;
notification.alertBody = #"Alert!";
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.applicationIconBadgeNumber = 1;
notification.soundName = UILocalNotificationDefaultSoundName;
switch (_frequencySegmentedControl.selectedSegmentIndex) {
case 0:
notification.repeatInterval = NSCalendarUnitDay;
break;
case 1:
notification.repeatInterval = NSCalendarUnitWeekOfYear;
break;
case 2:
notification.repeatInterval = NSCalendarUnitYear;
break;
default:
notification.repeatInterval = 0;
break;
}
notification.alertBody = _customMessage.text;
Once we have the notification created we need to schedule it with the app.
// this will schedule the notification to fire at the fire date
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
// this will fire the notification right away, it will still also fire at the date we set
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
If we leave things the way they are now a notification will only appear on screen if the app is in the background. In order to display something when the app is in the foreground and a notification fires we need to implement a method in the app delegate.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Notification Received" message:notification.alertBody delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alertView show];
}
We added a icon badge to our app, and this icon badge will only display when the app is in the background. Generally you want to dismiss the icon once a user has opened the app and seen the notification. We’ll need to handle this in the app delegate as well.
These two methods will take care of it.
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
NSLog(#"%s", __PRETTY_FUNCTION__);
application.applicationIconBadgeNumber = 0;
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
NSLog(#"%s", __PRETTY_FUNCTION__);
application.applicationIconBadgeNumber = 0;
}
iOS 10 by Apple document:
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:#"Hello!" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:#"Hello_message_body"
arguments:nil];
content.sound = [UNNotificationSound defaultSound];
// Deliver the notification in five seconds.
UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger
triggerWithTimeInterval:5 repeats:NO];
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:#"FiveSecond"
content:content trigger:trigger];
// Schedule the notification.
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:nil];