Local location notifications are not being delivered in iOS 12 - ios

I have an app which uses UNLocationNotificationTrigger to deliver notification based on user's location. When I'm testing my app sometimes it registers that user entered specific region, but doesn't deliver notification on entering region. Other times it works perfectly but I was wondering why this doesn't work every time. Does anyone else have similar problem? I would appreciate if someone could give a short explanation on this problem :)
This is the piece of code for registering notification:
let notification = UNMutableNotificationContent()
notification.title = "Notification title"
notification.subtitle = "Notification subtitle"
notification.body = "Notification body"
let notificationTrigger = UNLocationNotificationTrigger(region: enteredRegion, repeats: true)
let notificationRequest = UNNotificationRequest(identifier: "id12494", content: notification, trigger: notificationTrigger)
UNUserNotificationCenter.current().add(notificationRequest, withCompletionHandler: nil)

Related

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.

How to prevent multiple location notifications from being triggered

I have multiple location notifications registered, often they overlap with each other. I want to limit to one fired notification per day, but the problem is that I do not have any way to cancel all the pending notifications when app is killed and can only do it when BGAppRefreshTaskRequest is triggered (which is not a common thing most of the times). And the worst part is that if user is in overlapping area he'll receive multiple push notifications at once.
Code to register notification:
let content = UNMutableNotificationContent()
content.title = "Title"
content.body = "Body"
content.sound = .default
content.userInfo = ["locationNotificationId" : id]
content.categoryIdentifier = "geofenceNotifications"
let region = CLCircularRegion(center: location,
radius: CLLocationDistance(range),
identifier: id)
region.notifyOnEntry = true
region.notifyOnExit = false
let trigger = UNLocationNotificationTrigger(region: region, repeats: false)
let request = UNNotificationRequest(identifier: id,
content: content,
trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: { error in
if let error = error {
print(error)
}
})
What do I do to prevent other notifications being triggered after one is fired if app is in the background or killed?
Ok, so I managed to resolve the issue by monitoring region itself instead of using local push notification with UNLocationNotificationTrigger. The downsides are - I need to ask location access for background instead of "when in use" and I'm limited to 20 regions but it still better than uncontrolled flow of push notifications.
To read more about region monitoring: https://www.raywenderlich.com/5470-geofencing-with-core-location-getting-started#toc-anchor-004

iOS : How to remove remote notifications if app is not active?

I want to clear remote notifications so they don't add up in the Notification Center (like when you get a video call in WhatsApp or Messenger, only the last notification is displayed).
I tried to call (in didReceiveRemoteNotification):
let center = UNUserNotificationCenter.current()
center.removeDeliveredNotifications(withIdentifiers: ["notification_identifier"])
But it gets called only if the app is active. How can I do this if the app is in another state?
Thanks for your help.
After some research and thanks to Paulw1's answer, I found out there are two ways of doing this:
Remote only
Notifications can be collapsed remotely, you only have to send the notification with apns-collapse-id as a request header. Please note that it's only supported in HTTP/2 though. More information here.
Silent remote + local notification
The other way consists in sending a silent remote notification, with this kind of payload:
{
"type": "notification_type",
"aps" : {
"content-available": 1
}
}
It will call didReceiveRemoteNotification even if the app's state is inactive or background. Then, I create a local notification request (needs using UserNotifications, available from iOS10) :
let content = UNMutableNotificationContent()
content.body = "Notification message"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.25, repeats: false)
let request = UNNotificationRequest(identifier: "identifierToUpdate", content: content, trigger: trigger)
self.center.add(request, withCompletionHandler: nil)
The key to update the previous notification is to use the same request identifier.

Schedule a local notification(silent) to perform a custom task in background + swift ios

In our app, the user will clock-in when he starts his work. If the user forgets to clock-out, we will have to automatically clock him out after 24 hours from the clock-in time. The app might not be in the active/background state for such a long time. It might be terminated. So our idea is to post a local notification through which will execute the code in the background to clock him out. This notification has to be a silent notification. But our understanding from the research is that local notifications cannot be silent. So is there any other way we could achieve this? Or can we actually schedule a silent local notification?
class func generateLocalNotificationWith(timeInterval : TimeInterval, title : String, message : String, mobileTimeClockId: Int)
{
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
let content = UNMutableNotificationContent()
//adding title, subtitle, body and badge
content.title = title
content.body = message
let userInfoDictionary = ["badge":"0","content-available": "1"]
let dict = ["aps": userInfoDictionary, "MobileTimeClockId": mobileTimeClockId] as [String : Any]
content.userInfo = dict
//getting the notification trigger
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false)
//getting the notification request
let request = UNNotificationRequest(identifier: "SimplifiedIOSNotification", content: content, trigger: trigger)
//adding the notification to notification center
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
If you want a notification to be silent and do background work it has to be a push notification. A local notification can't wake your app without some user interaction.
The best way to do what you want is to use Core Location region monitoring to wake your app when the user physically leaves their workplace. Region monitoring can wake your app silently in the background and let you do some work. The problem is that it's not 100% assured that it will be triggered and the user will need to accept background location permissions.

Keep UNNotificationContent some seconds

I'm doing an app in Swift 3 for iOS 10. I have done an UNNotificationContent to simulate a call in my app but it disappears approximately five seconds after being launched. I need to keep it more seconds, while the "calling" is in process. I want to keep the local notification until I call the removeAllPendingNotificationRequests method. Can I do it?
This is my code now:
let content = UNMutableNotificationContent()
content.body = "\(userName) is calling..."
content.sound = UNNotificationSound(named: "sound_call.wav")
content.badge = 1
let request = UNNotificationRequest(identifier: "notification", content: content, trigger: nil)
UNUserNotificationCenter.current().add(request)
Thanks!
There's no way to control how long the notification stays on the screen. That's controlled by the system.

Resources