In iOS 7, when a user swipes one of my notifications from the lockscreen and is taken to my app, the notification sound keeps playing (unlike iOS 6). Is there any way to programmatically stop that sound when my app launches in iOS 7?
NOTE: see the accepted answer for a shoddy workaround.
I'm pretty sure this is a bug on Apple's end, see devforums.apple.com/message/888091 (thanks Gui13). File a duplicate bug report to get Apple to pay attention to it, as that is how Apple assigns priority to bugs. In the meantime, the following will work but will also clear all of your notifications in the notification center, which of course is a shoddy workaround, but in my case is worth it until this gets fixed:
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 1];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
it doesn't help by using
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 1];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];
after entering the app by clicking the notification.
I have solved this problem by sending another empty notification when dealing with the notification with sound:
if (notification.soundName != nil) {
if (IS_IOS7) {
UILocalNotification *emptyNotification = [[UILocalNotification alloc] init];
emptyNotification.timeZone = [NSTimeZone defaultTimeZone];
emptyNotification.fireDate = [NSDate date];
emptyNotification.alertBody = #"";
[[UIApplication sharedApplication] scheduleLocalNotification:emptyNotification];
}
}
For iOS 7, the accepted answer may be the only viable option. For developers who have come here that can support a minimum of iOS 10, this works.
You can remove all notifications from Notification Center by calling
UNUserNotificationCenter.current().removeAllDeliveredNotifications()
This has a very similar affect as the accepted answer: the audio stops playing and all the notifications are removed from Notification Center.
An improved solution is to use
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: [String])
This stops the audio for only the given notifications, and removes them from Notification Center.
To get the ids for all the delivered notifications, use
UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
let ids = notifications.map { $0.request.identifier }
}
Related
I'm adding a video chat to my app and use PushKit to get a pushNotification when the app is in the background. I Can't use the CallKit for video as it mess up the SDK I'm using so I have added a local push notification that fire up from the PushKit delegate method.
I'm wondering how Whatsapp does it with their Video call. For now they are showing a push notification but in a way that I can't recognize. The push is fired up with two vibrations and after two seconds there is a new push that overlaps the first notification and you can feel another two vibrations and so on until you answer. How do they do it as you can't add vibration over and over again and how do they delete the notification and establish a new one in the background as the NSTimer is not working in the background. If I add [[UIApplication sharedApplication] beginBackgroundTaskWithName:expirationHandler:] then I can use the timer for 180 seconds but only if the app was active.
So the real problem is how to add a local notification that can repeat itself few times and also add vibration to it?
For iOS 10 and later.
Use UNUserNotificationCenter:
let notificationContent = UNMutableNotificationContent()
// this sets sound + vibration
notificationContent.sound = UNNotificationSound.default
let trigger = UNTimeIntervalNotificationTrigger(
timeInterval: 1,
repeats: false
)
let request = UNNotificationRequest(
identifier: "notification_identifier",
content: notificationContent,
trigger: trigger
)
UNUserNotificationCenter.current().add(request) { _ in }
You can create a notification in the future and when it gets called cancel all the previous ones and reschedule until you're satisfied.
UILocalNotification* localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = body;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.fireDate = [NSDate new]; //<-Set the date here in 10seconds for example
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
Then in application didReceiveLocalNotification:(UILocalNotification *)notification:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
application cancelAllLocalNotifications;
}
I have a decryption and encryption method in my app. When the app enters the background, a file is encrypted. If the app entered the foreground, the file will be decrypted. Thats the main story. Both parts take some time and a lot of memory. In the background, Im doing something like that.
encryptionTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^(void) {
// Wwe took too long. Stop task.
}];
In the applicationWillEnterForeground, Im doing the following:
if (encryptionTaskId != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:encryptionTaskId];
}
I think that works well. But my problem is when someone clicks the home button during the applicationWillEnterForeground is decrypting my file. Again the applicationDidEnterBackground is starting, but my decrypting is not finished. What is the best way to handle that. Is it possible to also wait until the foreground finished?
Are you able to detect if the file is currently being accessed or being encrypted / decrypted? If so, create a timer to do the encryption / decryption again in a few seconds after the previous method has stopped.
UPDATE:
Please see http://developer.apple.com/library/ios/DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/ManagingYourApplicationsFlow/ManagingYourApplicationsFlow.html#//apple_ref/doc/uid/TP40007072-CH4-SW28 you should be able to use beginBackgroundTaskWithExpirationHandler:. Which will buy you extra time to finish processing before your app moves to the background.
UPDATE 2:
Make sure encryptionTaskId is an instance variable
- (void)applicationDidEnterBackground:(UIApplication *)application
{
encryptionTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
encryptionTaskId = UIBackgroundTaskInvalid;
}];
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
encryptionTaskId = UIBackgroundTaskInvalid;
}
Then in applicationDidEnterForeground you will want to check if encryptionTaskId is still working and if so create a timer to try again shortly to decode it.
in my app i schedule some UILocalNotification every time the app is opened, but happen that sometimes the uilocalnotification is not fired and don't notify me,and when happen they don't fired anymore, to fix it i have to reinstall the app on the iPhone, so i'm explain me well, there is a period of time that the notification work and then one day the dont' work anymore and to fix it i have to reinstall it again, so to investigate i have create this method that it's called when the app did become active:
-(void)checkNotification {
for (UILocalNotification *someNotification in [[UIApplication sharedApplication] scheduledLocalNotifications]) {
NSLog(#"%#",someNotification.alertBody);
NSLog(#"%#",someNotification.fireDate);
}
}
and i see that all notification are scheduled and also the date, this is an example:
2012-11-25 18:36:36.532 TestApp[672:907] This is a notification.
2012-11-25 18:36:37.482 TestApp[672:907] 2012-11-27 10:00:00 +0000
so i can't understand why i don't receive notification...any help?
Edit:
i create a notification in this way:
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.fireDate = myNewDate;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.alertBody = #"This is a notification.";
localNotification.soundName = #"smallBell.mp3";
[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];
You may or may not get the alert message. It depends on whether your app is running and in which state, e.g. active in the foreground, active in the background, or not running at all.
Please see this article for clarification - http://www.thekspace.com/home/component/content/article/62-uilocalnotification-demystified.html
So my app has been around for 5 days now and iPhone 3GS users are reporting that their notifications doesn't cancel when the button is switched.
The button executes the following code:
[[UIApplication sharedApplication] cancelAllLocalNotifications];
However, this code works on iPhone 4,iPhone 4S,iPhone 5 and iPad.
Is this a known bug of the iPhone 3GS? Or does the 3GS require different code to achieve the same thing?
I'm running into this problem on iOS 8.1 on an iPhone 6+. It turns out that cancelAllLocalNotifications is not a synchronous call, so there is no guarantee that the cancelation has been completed when it returns. I've had to implement the following as a workaround
- (void) clearNotifications
{
NSLog(#"Clearing notifications");
[[UIApplication sharedApplication] cancelAllLocalNotifications];
long count;
while ((count = [[[UIApplication sharedApplication] scheduledLocalNotifications] count]) > 0) {
NSLog(#"Remaining notificaitons to cancel: %lu",(unsigned long)count);
[NSThread sleepForTimeInterval:.01f];
}
NSLog(#"Notifications cleared");
}
Don't know why but I had to cancel all notification by notifcation ID instead of CancelAll on iPhone 3GS
FIXED — Ok, found what it was, there was an errant [[UIApplication sharedApplication] cancelAllLocalNotifications]; being fired when I wasn't expecting it.
Well there's your problem.
Thanks for the help everyone, sorry to have it turn out to just be dumb coder syndrome.
I've built out my local notification like so:
- (void)scheduleNotification {
[[UIApplication sharedApplication] cancelAllLocalNotifications];
Class cls = NSClassFromString(#"UILocalNotification");
if (cls != nil) {
UILocalNotification *notif = [[cls alloc] init];
NSLog(#"%#", [NSDate date]);
notif.fireDate = [NSDate dateWithTimeIntervalSinceNow:10];
notif.alertBody = NSLocalizedString(#"Hello.", nil);
[[UIApplication sharedApplication] scheduleLocalNotification:notif];
NSLog(#"Notification scheduled at %#", notif.fireDate);
[notif release];
}
}
As expected my debug log outputs the correct fireDate 10 seconds in the future. If I don't leave my app I get a successful application:didReceiveLocalNotification: callback.
The hiccup here is if I push the button to schedule this notification and hit the home button to put it in the background. If I do this, the notification never fires and I never get an alert view from the OS.
Did I miss something obvious here? I've looked up and down here and the Apple docs and feel I've missed something obvious.
Any help would be greatly appreciated. Thanks.
See the example in Apple's docs:
http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.html#//apple_ref/doc/uid/TP40008194-CH103-SW1
Could it be that not setting timeZone to [NSTimeZone defaultTimeZone] is causing the problem? GMT is assumed if timeZone isn't set (nil default).
Have you tried wrapping the code in a background task?
Ok, found what it was, there was an errant [[UIApplication sharedApplication] cancelAllLocalNotifications]; being sent when entering the background.