app is sending multiple notifications - ios

I want my app to send a single notification at a given time and repeat daily. The notification sends fine but it sends multiple notifications. So instead of sending 1, it sends 5. How can I fix this with code. I have 2 viewcontrollers if that is meaningful.
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
// ask for permission for notifications
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound], completionHandler: {didAllow, error in
})
// making the content of the notification
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Get Motivated"
content.body = "Need Some Motivation? We've Got Plenty!"
content.sound = UNNotificationSound.default()
//triggering notification
var dateComponents = DateComponents()
dateComponents.hour = 13
dateComponents.minute = 35
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request)

It's a little hard to be precise without seeing more of your code so forgive me if I misunderstood something. Nevertheless, here are some suggestions:
You are sending notifications every time your view controller's "viewDidLoad" method is called. For a bit of context, in earlier versions of iOS, in order to save memory, views were unloaded from memory when views were removed from view hierarchy (say, after a transition to a different full screen view); it is not done anymore, but "viewDidLoad" is not guaranteed to be called only once during the life time of a given view controller. In addition to that, if you instantiate and present a view controller of this class more than once, "viewDidLoad" will be called multiple times.
Your code, also, does not seem to take into account a possibility that the app might be launched more than once.
In order to ensure that only one notification is scheduled, you can:
Check for already scheduled notifications and see if the one you are trying to add is a duplicate (you can use UNUserNotificationCenter.getPendingNotificationRequestsWithCompletionHandler method for that);
Remove all already scheduled notifications and add new ones in their place (see UNUserNotificationCenter.removeAllPendingNotificationRequests).
The method you choose, of course, depends on the logic of your app.
Good luck!

Related

How To Create Alarm Notification Swift iOS?

I want to when user get notification from fcm (Firebase Cloud Messaging) or scheduler local notification like alarm notification like image below :
Here my code :
func onTest() {
let content = UNMutableNotificationContent()
content.title = "Weekly Staff Meeting"
content.body = "Every Tuesday at 2pm"
// Configure the recurring date.
var dateComponents = DateComponents()
dateComponents.calendar = Calendar.current
dateComponents.hour = 16 // 14:00 hours
dateComponents.minute = 11
// Create the trigger as a repeating event.
let trigger = UNCalendarNotificationTrigger(
dateMatching: dateComponents, repeats: true)
// Create the request
let uuidString = UUID().uuidString
let request = UNNotificationRequest(identifier: uuidString,
content: content, trigger: trigger)
// Schedule the request with the system.
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.add(request) { (error) in
if error != nil {
// Handle any errors.
}
}
}
My code right now just like the usual notification which disappears in 5 seconds I want to make it like an Alarm notification or Whatsapp Calling Notification. Please Help Thanks.
Due to Apple's limitation, app dev can only play notification tone up to 30 seconds. It will play default notification tone if your tone is longer than 30 seconds.
If your notification tone is gone after 5 seconds, try to set your notification presentation options to list, badge and sound.
Once there's no banner for notification, your 30seconds tone will play till the end.
Unfortunately there's no legal way or any workaround to have notification ring continuously such as alarm clock. Hope I was wrong though.
https://developer.apple.com/documentation/usernotifications/unnotificationpresentationoptions
What I think, max you can do is to present a local notification. But yes that would not be exactly like an Apple Alarm notification. In Reality, you don't have permission for this. You can only present the local notifications.

UNNotificationRequest to send local notification daily at a specific time

Since UILocalNotification was deprecated in iOS10, I'm having trouble understanding how to update the following code to the UNNotificationRequest framework. Im basically letting a user schedule a daily notification at a time of their choosing. For example, if they want to get a notification everyday at 11:00AM. The below code works for iOS versions below iOS10 but since UILocalNotification is deprecated, it no longer works. Any help is greatly appreciated.
let notification = UILocalNotification()
notification.fireDate = fixedNotificationDate(datePicker.date)
notification.alertBody = "Your daily alert is ready for you!"
notification.timeZone = TimeZone.current
notification.repeatInterval = NSCalendar.Unit.day
notification.applicationIconBadgeNumber = 1
UIApplication.shared.scheduleLocalNotification(notification)
You can use UNCalendarNotificationTrigger for creating a notification that fires repeatedly using UNUserNotificationCenter. You can do something like this. The trick is to only have the time component in the Trigger date.
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Attention!"
content.body = "Your daily alert is ready for you!"
content.sound = UNNotificationSound.default
let identifier = "com.yourdomain.notificationIdentifier"
var triggerDate = DateComponents()
triggerDate.hour = 18
triggerDate.minute = 30
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: true)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
center.add(request, withCompletionHandler: { (error) in
if let error = error {
// Something went wrong
print("Error : \(error.localizedDescription)")
} else {
// Something went right
print("Success")
}
})
You can't schedule a notification that repeats daily. That notification would happen only once, and then you would have to schedule it again, which means that you would have to open the app again.
There is BGTask API introduces in iOS 13, that can be used to perform some background tasks, but not this one, you can not schedule the task for specific time.This API last only works when app is in the background, not when it is killed. You can only set some time interval that the system will use as a guiding point to determine when to perform you app's code. But in my experience it is pretty unreliable.
The only way to achieve this is to implement remote push notifications. Push notifications also work even when the app is killed.

Problem in scheduling repeating local notification every hour

Im trying to schedule local notification every hour. The problem is that im getting the notification in such irregular time. Sometime in 10 minutes, or in second, or 30 minutes. Sometime i get like 10 notifications in the same second suddenly. I have no idea what is the mistake im doing here. I apologize in advance, i just started learning swift.
This is my code.
#objc func LocalNotificationHour() {
let user = UNUserNotificationCenter.current()
user.requestAuthorization(options: [.alert,.sound]) { (granted, error) in}
let content = UNMutableNotificationContent()
content.title = "Local Notification"
content.body = "Test."
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: (60*60), repeats: true)
let uuid = UUID().uuidString
let request = UNNotificationRequest(identifier: uuid, content: content, trigger: trigger)
user.add(request) { (error) in print("Error")}
}
Is it possible that your function is being run multiple times, and therefore scheduling more than one notification to repeat? That would account for receiving multiple notifications at once/at times when you're not expecting them.
If that is the case, try adding the line user.removeAllPendingNotificationRequests() under let user = UNUserNotificationCenter.current(). This will remove any pending notifications your app may have scheduled before scheduling a new one.
It's because you are running your code once with one hour logic.
And then you are changing logic for two hour logic.
So basically both notification is triggering.
Either delete the app or previously scheduled notifications or change the identifier.

iOS 11- User local notification which repeat every x minutes

In iOS 11, how can I implement a local notification which repeats every x minutes?
The repeating interval will be selected from the user. So for example let's say that a user choose to set a notification which will trigger tomorrow at 9:00 AM and from there it triggers every 2 days (or two weeks or 6 months or 10 minutes)
var repeatInterval = Bool()
trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: repeatInterval)
//Schedule the Notification
let identifier = titleNospace
let request = UNNotificationRequest(identifier: identifier!, content: content, trigger: trigger)
self.center.add(request, withCompletionHandler: { (error) in
if let error = error {
print(error.localizedDescription)
}
})
UNUserNotificationCenter.current().add(notificationRequest, withCompletionHandler: nil)
With this code I can schedule a notification at a set date. I've been told that from here if I would like to schedule a repeat notification I should use a triggerInterval when the notification is delivered.
But how can I do so? How can I get the value of the repeating time (defined by the user) when the notification is delivered?
Shall I use this?:
func didReceive(_ notification: UNNotification)
I've tried but it seems that it's never called.
I'm new to swift and I've tried and tried but it seems I cannot find a solution.
I've been able to manage the repeating hourly, monthly, daily and yearly.
If I would like to add a custom repeat though I really wouldn't know how to do.
For your information you can't do customise repeat time interval like every 2 min, 10 min or Etc. you must use value of NSCalendarUnit like
How to set repeat frequency in User Notification

How to dismiss 3D-touched notification with custom action?

I am implementing a kind of alert notification for my app, using UserNotifications. When 3D-touching this notification, I want it to display some 'alert information', and the option to "Snooze" the alert, which will effectively repeat the notification in 5 minutes.
This is all working fine, except that the notification doesn't get dismissed when I click the Snooze button.
I am using a NotificationContentExtension to modify the content, with the categoryIdentifier "ReminderNotificationExtensionCategory". Then I have created my category in code like this:
let snooze = UNNotificationAction(identifier: "snoozeActionIdentifier", title: NSLocalizedString("SNOOZE", comment: ""), options: .foreground)
let reminderCategory = UNNotificationCategory(identifier: "ReminderNotificationExtensionCategory", actions: [snooze], intentIdentifiers: [], options: .customDismissAction)
UNUserNotificationCenter.current().setNotificationCategories([reminderCategory])//Not sure if I should set this every time or just once..
Then I create my notification object
let content = UNMutableNotificationContent()
content.categoryIdentifier = "ReminderNotificationExtensionCategory"
content.title = "test"
content.body = "test"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false) //Fire in 3 seconds
let request = UNNotificationRequest(identifier: "someIdentifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error:Error?) in /**/}
Now, my notification will be sent in 3 seconds.
I lock my screen and receive it, and it looks great. When I 3D-touch it, my extension is launched, and I get a sneak peak on a UIView I have set up, along with my "Snooze"-button below the notification, as shown in the image:(content removed)
When I click the "Snooze"-button, a UNNotificationContentExtension delegate-method will be called, specifically func didReceive(_ response: completion:)
The completion only accepts a value of UNNotificationContentExtensionResponseOption, which would be either .dismiss, .doNotDismiss, or .dismissAndForwardAction.
Just for testing, I have done this:
func didReceive(_ response: UNNotificationResponse, completionHandler completion: #escaping (UNNotificationContentExtensionResponseOption) -> Void) {
print("This is happening. ActionIdentifier: ", response.actionIdentifier)
completion(.dismiss)
}
And when I debug the notification extension, the print does really happen. It prints out "This is happening. ActionIdentifier: snoozeActionIdentifier". However, the notification is not being dismissed.
If I change from .dismiss to .doNotDismiss, nothing changes. It still does not dismiss. If I change to .dismissAndForwardAction, it dismisses and opens my app.
I can't find anyone with this problem. I want .dismiss to dismiss my notification. Why isn't it? Am I doing something wrong?
Edit
I see now that these two scenarios are happening:
I 3D-touch my notification from the lock screen, then tap outside it, my notification 'collapses' and the regular notification is visible as it was before I 3D-touched it.
I 3D-touch my notification from the lock screen, tap 'Snooze' (and nothing happens), then tap outside the notification, and the regular notification disappears.
So the completion callback actually does dismiss the regular notification, but not the extension. Why? How can I dismiss the extension? Is that a manual method I must call?
I see my stupid mistake now..
As you can see in my code above, I have instantiated the action button in my category as such:
let snooze = UNNotificationAction(identifier: "snoozeActionIdentifier", title: NSLocalizedString("SNOOZE", comment: ""), options: .foreground)
At the very end, I specify the option .foreground. This should simply be an empty array [] for my purpose.
I thought I had to specify an option, and that the input type was of UNNotificationActionOptions, which only had the options .authenticationRequired ("no I don't want that") .destructive ("no I don't want a red button") and .foreground ("well, if I have to pick one if these.."). Turns out that simply specifying an empty array [] did the trick.

Resources