I am using local notifications in my app to alert urgent messages to the user. What happens is the user receives a push notification, then a local notification is created and fired 60 seconds later with a time interval of 60 seconds. This works great and the urgent notification fires every 60 seconds as expected.
The problem is after about 20 minutes the local notification stops firing. This does not occur all the time and sometimes the notification can fire for hours with no problem. However, this problem seems to occur more often than not.
On iOS 9 we did not experience this problem at all and the notification would fire repeatedly overnight even, so I am thinking this might be something related to iOS 10?
I've also got a hunch that perhaps this has to do with memory pressure from the OS? If I attach to xCode and debug then the problem does not occur at all and will fire into infinity.
The code I use to create the notification is as follows:
[[UNUserNotificationCenter currentNotificationCenter] getPendingNotificationRequestsWithCompletionHandler:^(NSArray<UNNotificationRequest *> * _Nonnull requests) {
dispatch_async(dispatch_get_main_queue(), ^{
//If notification already exists then kill it with fire
[self removeAllLocalNotifications];
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = #"Urgent";
content.sound = [UNNotificationSound soundNamed:#"dingdingding.wav"];
content.categoryIdentifier = #"urgentCategoryId";
content.body = #"You have an urgent message.";
// Deliver the notification in scheduled amount of seconds.
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:60 repeats:YES];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:#"urgentMessageId" content:content trigger:trigger];
// Schedule the notification.
[[UNUserNotificationCenter currentNotificationCenter] addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(#"Notification creation Error");
}
if (completionHandler) {
completionHandler(UIBackgroundFetchResultNewData);
}
});
}];
});
}];
Any help would be much appreciated as this is a very frustrating issue.
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 want to develop an alarm application in iOS. So far, I have created basic UI where the user can select the time when the alarm should trigger. The code schedules one local notification for this time using following code:
UNMutableNotificationContent *content = [UNMutableNotificationContent new];
content.title = #"Helloooooo...";
content.body = #"Time to wake up!";
content.sound = [UNNotificationSound defaultSound];
//create trigger
UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:triggerDate repeats:NO];
NSString *identifier = #"test";
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier
content:content trigger:trigger];
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Something went wrong: %#",error);
}
}];
Now, when this notification is triggered, I want to play music (like an alarm tone). After lot of research I understood that there are no callbacks for the notification triggered event when the application is in background.
Another approach I tried in which the code tries to call the playAlarmTone method after certain timer:
UIApplication *app = [UIApplication sharedApplication];
//create new uiBackgroundTask
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
//and create new timer with async call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//run function methodRunAfterBackground
NSTimer* t = [NSTimer scheduledTimerWithTimeInterval:lroundf(secondsBetween)
target:self
selector:#selector(playAlarmTone)
userInfo:nil
repeats:NO];
[[NSRunLoop currentRunLoop] addTimer:t forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] run];
});
But with this approach, the music is not playing if the alarm clock is set to more than 15 minutes from the current time.
I have following questions:
What are the methods/hacks to run specific task after time interval of "x" minutes?
What is the best approach to implement the alarm clock in iOS?
I would appreciate any suggestions and thoughts on this topic.
EDIT:
I found an alarm application on the App Store which can play alarm music for infinite time when alarm is triggered. How this app can determine when to start the alarm music?
You should specify the music name by setting the sound property to your content.
So instead of:
content.sound = [UNNotificationSound defaultSound];
You should set:
content.sound = [UNNotificationSound soundNamed:#"yourSoundName.mp3"];
Also, make sure that your music length is not longer than 30 seconds.
Did you already consider using NSTimer scheduledtimerwithtimeinterval? This could be used to perform an action after a time interval as per your need. Also, check this article http://andrewmarinov.com/building-an-alarm-app-on-ios/ from Andrew.
Hi i i have a local push notification problem.
I implemented in-app language change function in my app.
and i have to restart the app after changed for reflect changes all part of my app. so i use abort() method.
before abort app i scheduled notification like this
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:#"Hello!" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:#"Languaged changed. Touch to restart." arguments:nil];
content.sound = [UNNotificationSound defaultSound];
// Deliver the notification in five seconds.
UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:3 repeats:NO];
UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:#"FiveSecond" content:content trigger:trigger];
// Schedule the notification.
UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:nil];
abort();
i want to user come back to app by touching alert
but push message didn't come at all the time. sometimes it was came
and doesn't work again.
please help me if you know something about this issue.
Call abort() in completion handler:
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
abort();
}];
But anyway, calling abort() isn't good practice.
You shall not exit app (someone already posted it here https://stackoverflow.com/a/356342/6429711 and I believe Apple have it somewhere in guidelines).
You can change language without quitting app. When you generate app multiple bundles are generated. You can change localisation from separate bundles then.
Example:
extension String
{
// Get selected language
var localized: String {
return NSLocalizedString(self, tableName: nil, bundle: currentLanguageBundle, value: "", comment: "")
}
}
Where currentLanguageBundle is bundle based on the currently selected language.
My application in background or inactive mode then local notification not work. I have never receive local notification on watch.
Update: less then 3 minutes schedule a local notification it's work fine but more then 3 minutes it's not work. so how to resolve this issues?
As per my understanding My code is as follows.
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
center.delegate = self;
// Objective-C
UNMutableNotificationContent *content = [UNMutableNotificationContent new];
content.title = [NSString localizedUserNotificationStringForKey:#"Remider!" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:#"Your watch is out of range" arguments:nil];
content.sound = [UNNotificationSound defaultSound];
// Time
// 15 min
double timer = 15*60;
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:time
repeats:NO];
// Actions
UNNotificationAction *snoozeAction = [UNNotificationAction actionWithIdentifier:#"Track"
title:#"Track" options:UNNotificationActionOptionForeground];
// Objective-C
UNNotificationCategory *category = [UNNotificationCategory categoryWithIdentifier:#"UYLReminderCategory"
actions:#[snoozeAction] intentIdentifiers:#[]
options:UNNotificationCategoryOptionCustomDismissAction];
NSSet *categories = [NSSet setWithObject:category];
// Objective-C
[center setNotificationCategories:categories];
// Objective-C
content.categoryIdentifier = #"UYLReminderCategory";
NSString *identifier = [self stringUUID];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:identifier
content:content trigger:trigger];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (error != nil) {
NSLog(#"Something went wrong: %#",error);
}
}];
Appreciate if any suggestion or idea.
Make sure your iphone is locked. When it comes to notification, its about preference where to deliver that notification.
Run your watch app on simulator, from iPhone simulator schedule the notification and lock the iPhone simulator screen, keep the watch simulator active, in that case when notification is triggered , it will be delivered on your watch simulator. Same will be the case when you will test on actual devices.
Source Link
And when both iphone and watch is locked, preference is iphone.
UPDATE
Notification on Apple Watch
I'm firing a local notification. Since UILocalNotification class is deprecated in iOS 10, I have used UserNotifications.framework.
When I try to set the custom sound for the notification, the default sound is playing all time.
Here is my code:
- (IBAction)fireLocalNotification:(id)sender {
UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:#"Hello!" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:#"Hello_message_body"
arguments:nil];
content.sound = [UNNotificationSound soundNamed:#"sound.mp3"];
// 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:^(NSError *error){
if(!error){
NSLog(#"Completion handler for notification");
}
}];
}
My sound is fine; sound.mp3 is present in project bundle itself.
More info:
https://developer.apple.com/reference/usernotifications/unusernotificationcenter?language=objc
Try deleting the app from the device, clean and run the app again on device.
Sometimes, resources are not properly updated; I think that is the problem in your case.
Long audio-files are not supported.
Is your file longer then 30 seconds? If yes, it will not work. Only files shorter then 30 seconds are available. If the file is longer then 30 seconds then it will be replaced with default sound.
UNNotificationSound documentation