I have set a custom .aif 30 second file as the local notification sound name. And below is my code for scheduling the local notification.
//Function to schedule local notification
-(void)schedulelocalnotification:(NSDate *)particularfiredate ringtone: (NSString *)particularringtone name:(NSString *)alarmname info:(NSDictionary *)dicttext
{
UILocalNotification *notification = [[UILocalNotification alloc] init];
notification.fireDate = particularfiredate;
notification.soundName = [arrayAIFFFiles objectAtIndex:[arraysoundfilesnames indexOfObject:particularringtone]];
notification.alertBody = alarmname;
notification.userInfo = dicttext;
[[UIApplication sharedApplication] scheduleLocalNotification:notification];
}
But when the device is locked, and the user slides on the notification to enter the app, the sound keeps on playing even when the user enters the app. It continues to play even when the user quits/uninstalls the app.
Please suggest what could be the possible reasons.
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
[[NSUserDefaults standardUserDefaults] setValue:#"0" forKey:#"demo"];
NSLog(#"%i",[[[UIApplication sharedApplication] scheduledLocalNotifications] count]);
NSString *viewcontrollerstring = [notification.userInfo objectForKey:#"smiletosnooze"];
NSLog(#"++++++------%#",viewcontrollerstring);
}
PS: I checked - UILocalNotification stop sound after notification is dismissed and this - Stop UILocalNotification Sound on slide to view but it was of no help. :(
This appears to be an open bug with iOS 7 as filed here. It also seems that when a device is passcode-locked, this issue does not appear. A pretty ugly hack that worked for me is setting a value for the application badge number and removing it immediately when the app comes into foreground. A sample code would be:
- (void)applicationWillEnterForeground:(UIApplication *)application
{
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 1];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
}
EDIT:
Apparently, the above mentioned hack is not actually working on iOS 7.1+. The only work-around I found is the following, but I'm very hesitant in calling it an actual answer:
- (void)applicationWillEnterForeground:(UIApplication *)application
{
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil];
MPMusicPlayerController *musicPlayer = [MPMusicPlayerController applicationMusicPlayer];
[musicPlayer setVolume:0.0f];
}
But there are a number of serious flaws with the code above:
setVolume method is deprecated since iOS 7 (although apparently many apps are still using it)
You have at some point of your app to re-set the volume to a proper (non-zero level)
Setting the volume property will most definitely have side-effects in other apps that might be playing sounds or music at the same time
UPDATE September 18, 2014
This issue seems to be resolved on iOS 8.
Related
I am making an app in which user select time and video. When notification fire than I want that the select video should be played . How can i achieve that?
Here is my notification code.
-(void) scheduleLocalNotificationWithDate:(NSDate *)fireDate
{
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
localNotif.fireDate = fireDate;
localNotif.timeZone = [NSTimeZone localTimeZone];
localNotif.alertBody = #"Time to wake Up";
localNotif.alertAction = #"Show me";
localNotif.soundName = #"Tick-tock-sound.mp3";
localNotif.applicationIconBadgeNumber = 1;
localNotif.repeatInterval = NSCalendarUnitDay;
NSLog(#" date %lu",kCFCalendarUnitDay);
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
}
Any Syggestion?
Your code for scheduling a local notification looks good. Probably you should also add some data in the userInfo property of the local notification, so that when it fires, you can check that property and do something different (play a specific video) according to the data inside the userInfo.
Example:
NSDictionary *infoDict = [NSDictionary dictionaryWithObject:#"video1" forKey:#"videoName"];
localNotif.userInfo = infoDict;
Make sure that you also request user permission for using local notifications, otherwise the local notification will not fire.
Example:
UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
UIUserNotificationSettings *mySettings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:mySettings];
Now you need to handle the firing of the local notification when your app is in the 3 states: foreground, background/suspended and not running.
The app is running in the foreground. The local notification fires at the date you set it to. The following delegate method will get called by the system in AppDelegate:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
NSString *videoName = [notification.userInfo objectForKey:#"videoName"];
//do something, probably play your specific video
}
The app is running in the background or is suspended. The local notification is shown to the user (it fired at the date you set it to) and the user taps on it. The same delegate method as above (didReceiveLocalNotification) will get called by the system in AppDelegate:
The app is not running, the local notification is shown to the user (it fired at the date you set it to) and the user taps on it. The following delegate method will get called by the system in AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification *localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif)
{
//the app was launched by tapping on a local notification
NSString *videoName = [localNotif.userInfo objectForKey:#"videoName"];
// play your specific video
} else {
// the app wasn't launched by tapping on a local notification
// do your regular stuff here
}
}
I would recommend reading Apple's documentation regarding working with local notifications.
You can use the Media Player framework as recommended in Glorfindel's answer and you can find an example for playing a video in this StackOverflow answer.
Once the user opens your local notification, your app will be launched, and the - application:didFinishLaunchingWithOptions: of your UIApplicationDelegate will be called. The options dictionary will contain a UIApplicationLaunchOptionsLocalNotificationKey key, which contains the UILocalNotification. That should give you enough information to determine which video needs to be played, which you can do with the Media Player framework.
Im trying to implement the local notification to my app and I implemented the local notification but the problem is .... I'm not getting the Notification BANNER and SOUND when my app is in the foreground. But it is working good when my app is in background.
How to bring the notification banner and sound in foreground.. Is that possible?
this is my piece of code...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Handle launching from a notification
UILocalNotification *locationNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (locationNotification) {
// Set icon badge number to zero
application.applicationIconBadgeNumber = 0;
}
}
- (void)application:(UIApplication*)application didReceiveRemoteNotification:(NSDictionary*)userInfo
{
if (application.applicationState == UIApplicationStateActive ) {
NSLog(#"it entered active push");
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.userInfo = userInfo;
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.alertBody = userInfo[#"aps"][#"alert"][#"body"];
localNotification.alertLaunchImage= userInfo[#"acme1"];
localNotification.fireDate = [NSDate date];
localNotification.applicationIconBadgeNumber = 1;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application
{
// Remove the badge number
application.applicationIconBadgeNumber = 0;
}
-(void)application:(UIApplication*)application didReceiveLocalNotification:(UILocalNotification *)notification{
UIApplicationState state = [application applicationState];
if (state == UIApplicationStateActive) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Reminder"
message:notification.alertBody
delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
// Set icon badge number to zero
application.applicationIconBadgeNumber = 0;
}
If the app is active you will be notified by application:didReceiveLocalNotification: in app delegate only. There you can display custom banner like view on the top viewcontroller presented on the view hierarchy . Just look at the whatsapp notification when the app is open
If the application is active then you will not recieve any sound, badge or alert, however the application delegate application:didReceiveLocalNotification: will be called
From apple docs
If the application is foremost and visible when the system delivers the notification, no alert is shown, no icon is badged, and no sound is played. However, the application:didReceiveLocalNotification: is called if the application delegate implements it. The UILocalNotification instance is passed into this method, and the delegate can check its properties or access any custom data from the userInfo dictionary.
If your app is currently running and active (i.e. visible), you will not see the alert message. Instead iOS will deliver the notification to your app directly through the following method
- (void)application:(UIApplication *)application
didReceiveLocalNotification:(UILocalNotification *)notification
No it will not play a sound or show a banner. However in your apps delegate , did receive notification will still be called where you can then show an alert view if you wish to notify a user.
You can however add audio manually.
- (void) application:(UIApplication *)application didReceiveLocalNotification: (UILocalNotification *)notification
{
SystemSoundID systemSoundID;
NSURL *soundURL = [[NSBundle mainBundle] URLForResource:#"blip"
withExtension:#"mp3"];
AudioServicesCreateSystemSoundID((__bridge CFURLRef)soundURL, &systemSoundID);
AudioServicesPlaySystemSound(systemSoundID);
}
Local notification in Foreground
I send a LocalNotification like this:
UILocalNotification *notification = [UILocalNotification new];
notification.alertBody = #"Hello, open me";
notification.userInfo = #{#"TheKey": #"www.stackoverflow.com"};
notification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] presentLocalNotificationNow:notification];
and in AppDelegate I do use:
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
NSDictionary *userInfo = notification.userInfo;
NSURL *siteURL = [NSURL URLWithString:[userInfo objectForKey:#"TheKey"]];
[[UIApplication sharedApplication] openURL:siteURL];
}
It opens the URL in new broswer window but it takes like 5-10 seconds for the app to take that action. Is it possible to open browser immediatly when LocalNotification is opened?
On iOS 7 and prior your approach would indeed be the only one. This is because UILocalNotification is only used to open your app, i.e. call the AppDelegate's method application:didReceiveLocalNotification:. So, the first place indeed for you to perform any actions would be that method.
However, with iOS 8 interactive notifications have been introduced. These allow the user to perform a specified action without opening the app.
In the screenshot you see that the user just received a notification and now has the option to perform certain actions on it, without actually going back into the app. You can find a great tutorial on how to implement interactive notifications here!
Im working on an app that does some computationally heavy tasks that take a long time. I want to notify the user with a local push notification when the task is done. Is this possible? The only information I have been able to find online is to do with triggering notifications at certain times/dates or if the app has entered the background or terminated, all of which is done in the appDelegate. Is there a way to do this in my own classes?
Thanks.
I'm not 100% certain you're looking for a UILocalNotification example because the post title mentions push notifications. Either way, you can schedule local notifications from any class you want
- (void)throwLocalNotificationWithMessage:(NSString*)message {
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
NSDate *now = [NSDate date];
localNotification.fireDate = now;
localNotification.alertBody = message;
localNotification.soundName = UILocalNotificationDefaultSoundName;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
[UIApplication sharedApplication].applicationIconBadgeNumber++;
}
Also, for my needs I throw these local notifications when region monitoring detects boundary enter/exit changes. This code runs while my app is in the background, as well, and in that case they appear like push notifications.
The above answer by Aaron works fine but don't forget to ask permission for Local Notification. In my case case I ask permission at AppDelegate under -
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
and here is the code for iOS8 and iOS9
if ([application respondsToSelector:#selector(registerUserNotificationSettings:)]) {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
I've been struggling for the past few days on the local notifications on my app.
Basically the goal is to pop a notification when the user approches an address.
here is the code:
NSMutableArray *notifications = [#[] mutableCopy];
for (CCAddress *address in results) {
CCCategory *category = [address.categories.allObjects firstObject];
NSDictionary *userInfo = #{#"addressId" : address.identifier};
UILocalNotification *localNotification = [UILocalNotification new];
if (category == nil)
localNotification.alertBody = [NSString stringWithFormat:#"Vous ĂȘtes proche de %#", address.name];
else
localNotification.alertBody = [NSString stringWithFormat:#"Vous ĂȘtes proche de %#, %#", address.name, category.name];
localNotification.alertAction = #"Linotte";
localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.userInfo = userInfo;
[notifications addObject:localNotification];
address.lastnotif = [NSDate date];
}
[managedObjectContext saveToPersistentStore:NULL];
[UIApplication sharedApplication].scheduledLocalNotifications = notifications;
The result is actually totally random, but there is something I know for sure: the geofencing works well, as you can see I set the date of the notification in lastNotif, so I know when they are fired.
Sometimes I see the notification pop, but doesn't stay in the notification center, but most times nothing happens, even if I see by the date that It actually fired, and sometimes everything goes fine.
I tried many things, like using presentLocalNotificationNow, setting a fireDate with a 1 second delay between each, and other things I don't even remember...
So, obviously there is something I missed in the documentation, but what ?
thanks.
PS: the app is in background or off when it happens, I'm aware of didReceiveLocalNotification.
PS2: I actually don't know if those that I don't see at all actually fired, because they don't show up in the notification center, so maybe they fired but I have absolutely no way to see them if I don't have my phone's screen in sight when they do.
EDIT: So, I've been doing some tests around my house, phone closed, screen locked. The real syndrom is that when a notification pops, it only turns the screen on, and the phone vibrates (I was sound off), then nothing...
I don't see that you're setting a fireDate. I can't recall what that defaults to.
Ok, so as intended, it was kind of stupid.
Before the code I posted I had:
if ([results count] == 0) {
[UIApplication sharedApplication].applicationIconBadgeNumber = 0;
return;
}
But, when you set applicationIconBadgeNumber to 0, it removes all notifications from notification center !
The documentation says nothing about this (https://developer.apple.com/library/ios/documentation/uikit/reference/UIApplication_Class/Reference/Reference.html).
You need to add registerUserNotificationSettings in didFinishLaunchingWithOptions it give us notification Alert
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
if ([UIApplication instancesRespondToSelector:#selector(registerUserNotificationSettings:)]){
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound categories:nil]];
}
UILocalNotification *localNotification = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotification) {
application.applicationIconBadgeNumber = 0;
}
return YES;
}