Why Scheduled UNUserNotification never fire? - ios10

I have a function for schedule a UNUserNotification, I put it into a sample xcode project then it's work - the notification are shown.
But, when I bring it to real project (company's project) then UNUserNotification never show.
here are my code
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
// create a category
UNNotificationCategory *inviteCategory = [UNNotificationCategory categoryWithIdentifier:#"kNotificationCategoryToDoIdentifier"
actions:#[]
intentIdentifiers:#[]
options:UNNotificationCategoryOptionCustomDismissAction];
NSSet *categories = [NSSet setWithObject:inviteCategory];
// registration
[center setNotificationCategories:categories];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *fireDateomponents = [gregorian components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond)
fromDate:[NSDate date]];
NSDateComponents * dateComponents = [[NSDateComponents alloc] init];
dateComponents.calendar = gregorian;
dateComponents.timeZone = [NSTimeZone localTimeZone];
dateComponents.year = fireDateomponents.year;
dateComponents.month = fireDateomponents.month;
dateComponents.day = fireDateomponents.day;
dateComponents.hour = fireDateomponents.hour;
dateComponents.minute = fireDateomponents.minute;
dateComponents.second = fireDateomponents.second + 10;
//Setup notification Triger
UNCalendarNotificationTrigger * trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents
repeats:NO];
UNMutableNotificationContent * content = [UNMutableNotificationContent new];
content.title = #"params.title";
content.body = #"params.body";
content.sound = [UNNotificationSound defaultSound];
content.badge = #(10);
content.categoryIdentifier = #"kNotificationCategoryToDoIdentifier";
//Crreate Notification Request
UNNotificationRequest * request = [UNNotificationRequest requestWithIdentifier:#"requestId"
content:content trigger:trigger];
//Schedule Notification
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * theError){
NSLog(#"Scheduled : %#", [dateComponents date]);
NSLog(#"WScheduled");
}];
Please help me !
Thanks a lot!

You should check your trigger.nextDate. I guess your trigger.nextDate is the time which you set trigger, but when the request is added into center, the nowtime is later than trigger.nextDate. So UNUserNotification never shows.
Have a try at
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * theError){
NSLog(#"Scheduled : %#", [dateComponents date]);
NSLog(#"Scheduled1 : %#", [trigger nextDate]);
NSLog(#"Scheduled2 : %#", [NSDate date]);
NSLog(#"WScheduled");
}];

Related

How to schedule UILocalNotification at Every Other Day or Every Third Day?

I have schedule UILocalNotification in my application at 10:00 AM Every Day.
I have used following code for this
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar] ;
NSDateComponents *componentsForReferenceDate =
[calendar components:(NSDayCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit ) fromDate:[NSDate date]];
[componentsForReferenceDate setDay:10] ;
[componentsForReferenceDate setMonth:10] ;
[componentsForReferenceDate setYear:2013] ;
NSDate *referenceDate = [calendar dateFromComponents:componentsForReferenceDate] ;
// set components for time 10:00 a.m.
NSDateComponents *componentsForFireDate =
[calendar components:(NSYearCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit| NSSecondCalendarUnit ) fromDate: referenceDate];
[componentsForFireDate setHour:10] ;
[componentsForFireDate setMinute:0] ;
[componentsForFireDate setSecond:0] ;
NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForFireDate];
// Create the notification
UILocalNotification *notification = [[UILocalNotification alloc] init] ;
notification.fireDate = fireDateOfNotification ;
notification.timeZone = [NSTimeZone localTimeZone] ;
notification.alertBody = [NSString stringWithFormat: #"Good Morning! Have a great day!"] ;
notification.alertAction = #"go back";
notification.userInfo= [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"Some information"] forKey:#"information"];
notification.repeatInterval = NSDayCalendarUnit ;
notification.soundName = UILocalNotificationDefaultSoundName;
notification.applicationIconBadgeNumber = [[UIApplication sharedApplication] applicationIconBadgeNumber] + 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notification] ;
It's working very good.
but now I want to schedule UILocalNotification at Every other day and every third day.
so how to do this?
You can not do customization of repeatTimeInterval of UILocalNotification.. there are many question as same like yours and also some days ago I had same question but i can not find any solution so please better is stop fight with it.
You must need to use repeat time interval from
Calendar Units
Specify calendrical units such as day and month.
enum {
NSEraCalendarUnit = kCFCalendarUnitEra,
NSYearCalendarUnit = kCFCalendarUnitYear,
NSMonthCalendarUnit = kCFCalendarUnitMonth,
NSDayCalendarUnit = kCFCalendarUnitDay,
NSHourCalendarUnit = kCFCalendarUnitHour,
NSMinuteCalendarUnit = kCFCalendarUnitMinute,
NSSecondCalendarUnit = kCFCalendarUnitSecond,
NSWeekCalendarUnit = kCFCalendarUnitWeek,
NSWeekdayCalendarUnit = kCFCalendarUnitWeekday,
NSWeekdayOrdinalCalendarUnit = kCFCalendarUnitWeekdayOrdinal,
NSQuarterCalendarUnit = kCFCalendarUnitQuarter,
NSWeekOfMonthCalendarUnit = kCFCalendarUnitWeekOfMonth,
NSWeekOfYearCalendarUnit = kCFCalendarUnitWeekOfYear,
NSYearForWeekOfYearCalendarUnit = kCFCalendarUnitYearForWeekOfYear
NSCalendarCalendarUnit = (1 << 20),
NSTimeZoneCalendarUnit = (1 << 21),
};
typedef NSUInteger NSCalendarUnit;
Above you can found from Apple's documentation. also read this question...
How to set Local Notification repeat interval to custom time interval?
For more information , you only scheduled local notification maximum 64, so be careful if may be you have planing in you mind that, you want to create multiple notification for do custom repeat time intervals..
You can't do this simply with repeatInterval, because only the following intervals are available.
One of the solutions I can think of would be to set separate notifications for each day (without repeatInterval). But by doing it in this way you can stumble on 64 notifications limit.

Local notifications are not coming on the datetime I want

I'm working with local notification. I got the notifications working. But I'm struggling with setting the correct date.
Let me first sketch the situation. I am making a festival app. This festival is on the 28-29-30 JUNE. Every artist object has an art_day. This can be 1 - 2 or 3.
1 --> 28 JUNE
2 --> 29 JUNE
3 --> 30 JUNE
I want a local notification 15 min before the start time of the artist. So this is how I'm making my fireDate of the notification.
-(NSDate *)getDateForArtist:(Artists *)artist{
int day = [artist.art_day intValue];
int timeStart = [artist.art_timestart intValue];
NSString *timeStart2 = [self getTimeStamp:artist.art_timestart];
int hours = [[timeStart2 substringWithRange:NSMakeRange(0,2)]intValue];
int minutes = [[timeStart2 substringWithRange:NSMakeRange(2,2)]intValue];
//in my db timeStart looks like 1530 --> 15h30 (I know bad db structure!!!)
int day2;
if(day == 1){
NSLog(#"day is 28");
day2 = 28;
}else if (day == 2){
NSLog(#"day is 29");
day2 = 29;
}else{
NSLog(#"day is 30");
day2 = 30;
}
NSDateComponents *comps = [[NSDateComponents alloc] init];
NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:#"GMT"];
[comps setTimeZone:timeZone];
[comps setDay:day2];
[comps setMonth:06];
[comps setYear:2013];
[comps setHour:hours];
[comps setMinute:minutes];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *date = [gregorian dateFromComponents:comps];
NSLog(#"date is %#",date);
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setMinute:-15];
NSDate *date2 = [gregorian dateByAddingComponents:offsetComponents toDate:date options:0];
NSLog(#"date -15 min %#", date2);
return date2;
}
This is how I create my notification
UIApplication* app = [UIApplication sharedApplication];
UILocalNotification* notifyAlarm = [[UILocalNotification alloc]
init];
if (notifyAlarm)
{
NSDate *datePush = [self getDateForArtist:artist];
NSLog(#"artist plays on: %# on hour %#",artist.art_day,artist.art_timestart);
NSLog(#"Push notification should send on: %#",datePush);
notifyAlarm.fireDate = datePush;
NSDictionary *dicNotification = [[NSDictionary alloc]initWithObjectsAndKeys:artist.art_id,#"pushKey", nil];
notifyAlarm.userInfo = dicNotification;
notifyAlarm.timeZone = [NSTimeZone defaultTimeZone];
notifyAlarm.repeatInterval = 0;
notifyAlarm.soundName = #"Glass.aiff";
notifyAlarm.alertBody = [NSString stringWithFormat:#"%# starts in 15 minutes",artist.art_name];
[app scheduleLocalNotification:notifyAlarm];
NSLog(#"Added");
}
But for some reason I don't get any push notification. Or I think that the date is not correct.
This is what I get from my logs
2013-06-29 15:37:17.801 genkonstage[14120:907] artist plays on day: 2 on hour 2020
2013-06-29 15:37:17.803 genkonstage[14120:907] Push notification should send on: 2013-06-29 20:05:00 +0000
Can anybody help me with this?

Is it possible to have a Conditioned `firedate` for UILocalNotification?

I'm trying to have a conditioned firedate time for my local notifications, however when I tried these two ways it didn't fail but it still didn't work. So, I was wondering if I'm able to do such a thing?
Note: startTime and endTime are times from date pickers.
-(void) TEST {
NSCalendar *calendar = [NSCalendar currentCalendar];
calendar.timeZone = [NSTimeZone timeZoneWithName:#"GMT"];
NSDateComponents *components = [calendar components:NSHourCalendarUnit fromDate:[NSDate date]];
components.hour = 3;
components.minute = (components.minute + 1) % 60;
components.second = 57;
NSDate *fire = [calendar dateFromComponents:components];
UILocalNotification *notif = [[UILocalNotification alloc] init] ;
if (notif == nil)
return;
if (fire < startTime.date) {
notif.fireDate =fire ;
notif.repeatInterval= NSMinuteCalendarUnit ;
notif.alertBody = [NSString stringWithFormat: #"You are missed!"] ;
[[UIApplication sharedApplication] scheduleLocalNotification:notif] ;
}
if (fire > endTime.date) {
notif.fireDate =fire ;
notif.repeatInterval= NSMinuteCalendarUnit ;
notif.alertBody = [NSString stringWithFormat: #"You are missed!"] ;
[[UIApplication sharedApplication] scheduleLocalNotification:notif] ;
}}
OR
-(void) TEST {
NSCalendar *calendar = [NSCalendar currentCalendar];
calendar.timeZone = [NSTimeZone timeZoneWithName:#"GMT"];
NSDateComponents *components = [calendar components:NSHourCalendarUnit fromDate:[NSDate date]];
components.hour = 3;
components.minute = (components.minute + 1) % 60;
components.second = 57;
NSDate *fire = [calendar dateFromComponents:components];
UILocalNotification *notif = [[UILocalNotification alloc] init] ;
if (notif == nil)
return;
if (fire > startTime.date & fire < endTime.date) {
[[UIApplication sharedApplication] cancelAllLocalNotifications] ;
}
else {
notif.fireDate =fire ;
notif.repeatInterval= NSMinuteCalendarUnit ;
notif.alertBody = [NSString stringWithFormat: #"You are missed!"] ;
[[UIApplication sharedApplication] scheduleLocalNotification:notif] ;
}}
Thanks
If not, what would be the easiest way to make such a condition?
use the NSDate Compare: method instead of if(fire > startTime.date)
if([fire compare: startTime.date] == NSOrderedDescending) // if start is later in time than end
{
// do something
}
From the class reference:
If:
The receiver and anotherDate are exactly equal to each other, NSOrderedSame.
The receiver is later in time than anotherDate, NSOrderedDescending.
The receiver is earlier in time than anotherDate, NSOrderedAscending.
so for your condition
if (fire > startTime.date & fire < endTime.date) {
[[UIApplication sharedApplication] cancelAllLocalNotifications] ;
}
you can use
if([fire compare: startTime.date] == NSOrderedDescending && [fire compare: endTime.date]== NSOrderedAescending)
{
[[UIApplication sharedApplication] cancelAllLocalNotifications] ;
}
this will cancel the all local notifications if fire is between the selected start and end date
else {
// Fire the notifications
}
also have a look at the link this is similar to what you need link
what i, will try do do is, when the sleep Time starts,call a method eg: goingToSleep:, you can use
dispatch_later or performSelector:withObject:afterDelay: for that,
in goingToSleep:
NSArray* localNotifications = [[UIApplication sharedApplication]
scheduledLocalNotifications];
for (UILocalNotification *notification in localNotifications)
{
if([fire compare: startTime.date] == NSOrderedDescending &&
[fire compare: endTime.date]== NSOrderedAescending)
{
This is the important part
get all the properties of the notification
create a NSDictionary of those properties
Add the NSDictionary to an array
and save that array into a plist.(Save Array to Plist)
and then Cancel that notification using
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
then after SleepTime is over
, again call a method eg: wakingUp:
then in wakingUp:
read the array of NSDictionary we saved.
again Create UILocalnotifications using those same Properties.
this way, no UILocalNotifications will trigger during sleep time. one issue can be executing those methods, if the Application is not memory.
EDIT To have long Running Appicaions.

Schedule local Notification after app was closed for 7 days

It was quite a bit hard to enable local notifications for my application.
And yeah, I set up my project with a local notification witch I want to schedule after the app had been closed for one week. For example if the user opens the app on saturday 8th, the local notification should appear on the next saturday the 15th, but the time should changed. For example he/she closes the app at 8pm and I don't want to disturb them at 8pm next week so I want to display every notification at 6pm or something like that.
Now you know my problem and here is my code I'm using:
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[[UIApplication sharedApplication] cancelAllLocalNotifications];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar] ;
NSDateComponents *componentsForReferenceDate = [[NSDateComponents alloc] init];
//set day (saturday)
[componentsForReferenceDate setDay:26] ;
[componentsForReferenceDate setMonth:1] ;
[componentsForReferenceDate setYear:2013] ;
[componentsForReferenceDate setHour: 17] ;
[componentsForReferenceDate setMinute:30] ;
[componentsForReferenceDate setSecond:00] ;
NSDate *fireDateOfNotification = [calendar dateFromComponents: componentsForReferenceDate];
// Create the notification
UILocalNotification *notification = [[UILocalNotification alloc] init] ;
notification.fireDate = fireDateOfNotification ;
notification.timeZone = [NSTimeZone localTimeZone] ;
notification.alertBody = [NSString stringWithFormat: #"Du wirst vermisst! \nDeine App braucht dich, schreibe sie zu Ende!"] ;
notification.alertAction = #"Zurückkehren";
notification.userInfo= [NSDictionary dictionaryWithObject:[NSString stringWithFormat:#"Some information"] forKey:#"information"];
notification.repeatInterval= NSWeekCalendarUnit ;
notification.soundName = #"Appnotifisound.wav";
notification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:notification] ;
}
I know that there have to be more methods for deleting the badge and the didrecievenotification, but I let them out because there are not important for this.
With this code I managed to schedule the notification on every saturday at 5:30pm (Germany). But I wanted to schedule it only once, when the app had been closed for exactly one week. Is that somehow possible? I would be glad if someone could correct my code or give me a solution for this.
Best regards and thank you for reading this long post,
Noah
You should unschedule previous notification.
for (UILocalNotification *lNotification in [[UIApplication sharedApplication] scheduledLocalNotifications])
{
if ([[lNotification.userInfo valueForKey:#"information"] isEqualToString:#"Some information"])
{
[[UIApplication sharedApplication]cancelLocalNotification:lNotification];
break;
}
}
Set fire date by below way:
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *componentsForReferenceDate = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate:[NSDate date]];
[componentsForReferenceDate setHour: 17] ;
[componentsForReferenceDate setMinute:30] ;
[componentsForReferenceDate setSecond:00] ;
NSDate *tempDate = [calendar dateFromComponents: componentsForReferenceDate];
[componentsForReferenceDate release];
NSDateComponents *comps = [[NSDateComponents alloc]init];
[comps setDay:7];
NSDate *fireDateOfNotification = [calendar dateByAddingComponents:comps
toDate:tempDate options:0]
[comps release];
The notification.repeatInterval = NSWeekCalendarUnit is causing this. use:
notification.repeatInterval = 0;
This prevent repeating (source).
Here is the Swift 2.0 adaptation
Unscheduling the current notification
for notifMe:AnyObject in UIApplication.sharedApplication().scheduledLocalNotifications!{
let title = notifMe.userInfo["information"] as? String
if title == "some information"{
UIApplication.sharedApplication().cancelLocalNotification(notifMe as! UILocalNotification)
}
}
Setting the date for the notification
let date = NSDate()
let calendar = NSCalendar.currentCalendar()
let components = calendar.components(NSCalendarUnit.Year.union(NSCalendarUnit.Month).union(NSCalendarUnit.Day),fromDate: date)
components.hour = 17
components.minute = 30
components.second = 00
let tempDate = calendar.dateFromComponents(components)!
let comps = NSDateComponents()
comps.day = 7
let fireDateOfNotification = calendar.dateByAddingComponents(comps, toDate: tempDate, options:[])

iOS notification override Silent mode - iPhone Alarm Clock App

I am working on an alarm clock App
The alert + music channels through the notification centre
It will not activate if the iPhone is set to silent mode
Many users have requested that the alarm overrides silent mode
Is this possible?
Cheers!
(void)addLocalNotification:(myAlarmData *)ma WeekDay:(int)mweekday
{
UILocalNotification *noti = [[UILocalNotification alloc] init];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *now = [NSDate date];
NSDateComponents *dcom = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit |NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit | NSWeekdayCalendarUnit) fromDate:now];
[dcom setWeekday:mweekday];
[dcom setHour:ma.mHour];
[dcom setMinute:ma.mMinute];
[dcom setSecond:0];
NSDate *fireDate = [gregorian dateFromComponents:dcom];
noti.fireDate = fireDate;
noti.timeZone = [NSTimeZone localTimeZone];
noti.alertBody = [NSString stringWithFormat:#"Wake up %#!", [GlobalData gSettings].name];
noti.soundName = [NSString stringWithFormat:#"%#.caf", ma.soundName];
noti.alertAction = #"OK";
noti.repeatInterval = NSWeekCalendarUnit;
noti.userInfo = [[[NSDictionary alloc] initWithObjectsAndKeys:
ma.mid, #"mid",
[NSString stringWithFormat:#"%d", mweekday], #"day",
ma.soundName, #"sound",
[NSString stringWithFormat:#"%d", ma.snooze], #"snooze",
ma.title, #"title",
#"Close", #"action",
#"real", #"more",
nil] autorelease];
[[UIApplication sharedApplication] scheduleLocalNotification:noti];
[noti release];
[gregorian release];
}
We can override silent switch to play sounds.
In this case it depends on how iOS manages to play sounds when a notification is triggered.
Have you checked this on device.?
You should take a look at AudioSession categories.
AVAudioSessionCategoryPlayback should do the trick.