I have a Firebase listener that launches a notification when it fires like so:
chat.ref.child("lastMessage").observe(.value, with: { snapshot in
let lastMessage = snapshot.value as! String
chat.lastMessage = lastMessage
self.tableView.reloadData()
chat.lastMessageText = "New Message!"
let content = UNMutableNotificationContent()
content.title = "You have a new Message!"
content.subtitle = chat.title
content.body = chat.lastMessage
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger (timeInterval: 1, repeats: false)
let request = UNNotificationRequest(identifier: "timerDone", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
Also have:
override func viewDidLoad() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge], completionHandler: {didAllow, error in })
}
The problem I am having is, although the HomeScreen notifications are working in the simulator, they are not showing on the device. All permissions are granted on the device. Reading some questions here I found some answers that suggested I add the following in the app delegate:
application.beginBackgroundTask(withName: "showNotification", expirationHandler: nil)
but this actually disabled notifications on the simulator too. The notifications did work on the device before but stopped very suddenly. Any thoughts?
Related
For a few months, I have been working on an app which uses local UNNotifications to achieve the grand goal. I coded this app using Swift 4, therefore aiming it towards distribution on the iOS App Store. As I was testing my app out, I noticed that after I clicked on one of the notification actions (which was not "cancel"), or if I just tapped on the notification in general, the app would open up (which is intended), but the notification would remain on the screen. Is there any possible way to remove the notification from the screen after already tapping on one of the actions programmatically? Below is the code where I schedule the notification:
let action1 = UNNotificationAction(identifier: "go", title: "Go", options: [.foreground])
let action2 = UNNotificationAction(identifier: "cancel", title: "Cancel", options: [.destructive])
let actionsCategory = UNNotificationCategory(identifier: "actions.category", actions: [action1, action2], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([actionsCategory])
//Queue the notification alert
let content = UNMutableNotificationContent()
content.body = "Interesting day notification!"
content.sound = UNNotificationSound.default()
content.setValue(true, forKey: "shouldAlwaysAlertWhileAppIsForeground")
content.categoryIdentifier = "actions.category"
// if (pinNumber.text) != nil{
// }
content.userInfo = ["Name": namePerson.text ?? "", "Pin": Int(pinNumber.text ?? "") != nil ? pinNumber.text! : ""]
//trigger
let triggerDate = Calendar.current.dateComponents([.year,.month,.day,.hour,.minute], from: datePicker.date)
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: false)
//scheduling
let identifier = id // set same id as task
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
center.add(request, withCompletionHandler: {(error) in
if let error = error{
print(error)
}else{
print("saved alert")
}
})
I don't see anything in your code that would cause that behavior. This sounds to me like either an iOS bug, or there is something weird about the notification permissions/settings of the particular device (or simulator) for your app. Go into the notifications sections of the Settings app and see what the settings are for your app.
I am trying to learn how to use local notifications and currently I am just trying to let a notification pop up when a certain time has passed (for the sake of learning just 5 seconds).
I register the notification in this function, which is used at the end of an onBoarding screen:
func registerNotification() {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
print("Granted.")
} else {
print("Not granted.")
}
}
}
Now to test the notification I just add the function set() to a button:
set() {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Test Notification"
content.body = "It works!"
content.categoryIdentifier = "alarm"
content.userInfo = ["customData": "fizzbuzz"]
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request)
}
But when the button is pressed and 5 seconds passed, no notification is shown, but also no error in Xcode, so I suppose this should all work?
What am I missing here? As far as I understand from various sources on the net this is the easiest way to display a local notification?
So to register a UserNotification and call the function at an appropriate
place:
func registerNotification() {
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
print("Granted.")
} else {
print("Not granted.")
}
}
}
This functions sets a notification with a time interval of 5 seconds. When the app is closed the notification will be displayed:
set() {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Test Notification"
content.body = "It works!"
content.categoryIdentifier = "alarm"
content.userInfo = ["customData": "fizzbuzz"]
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request)
}
I'm making an app that used circular regions for geofences. When the phone is active or the app is open, the geofence notifications are working fine in both simulator and device (iPhone 6 running 10.3.1).
In the simulator it works fine; When the user enters a region, it wakes up, makes a sound and shows an alert on the lock screen.
On the phone, the "didEnterRegion" delegate calls are made when entering the region (I log some messages) but the phone is not making an alert and waking up. When I push the home button once, I can see the alert on the lock screen, but I want it to wake up and show the alert instantly - like when I get a message. It works in the simulator, so I wonder what could be wrong? It has worked for me a few times, where the alert was shown on both the phone and my watch, but 95% of the time it's not working - the notifications are generated but only visible if I manually wake up the phone.
How to fix this?
Here's the code I use for creating the local notification:
// https://blog.codecentric.de/en/2016/11/setup-ios-10-local-notification/
let location = CLLocation(latitude: item.coordinate.latitude, longitude: item.coordinate.longitude)
GeoTools.decodePosition(location: location) {
(address, city) in
let content = UNMutableNotificationContent()
content.title = "Camera nearby!"
content.subtitle = item.id
content.body = "\(address), \(city)"
content.categoryIdentifier = Constants.notificationCategoryId
content.sound = UNNotificationSound.default()
content.threadIdentifier = item.id
// FIXME make action for clicking notification
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.001, repeats: false) // FIXME HACK
let request = UNNotificationRequest(identifier: "camNotification", content: content, trigger: trigger)
let unc = UNUserNotificationCenter.current()
unc.removeAllPendingNotificationRequests()
unc.add(request, withCompletionHandler: { (error) in
if let error = error {
print(error)
}
else {
print("completed")
}
})
}
Here is some code that I just verified wakes the device when notification is presented:
let message = "CLRegion event"
// Show an alert if application is active:
if UIApplication.shared.applicationState == .active {
if let viewController = UIApplication.shared.keyWindow?.rootViewController {
showSimpleAlertWithTitle(nil, message: message, viewController: viewController)
}
}
else {
// Otherwise app is in background, present a local notification:
let content = UNMutableNotificationContent()
content.body = message
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "message"
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 1.0, repeats: false)
let request = UNNotificationRequest(identifier: "com.foobar", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
Really the only diff is that I don't call removeAllPendingNotifications() so if you must remove notifications I wonder if removePendingNotificationRequests(withIdentifiers identifiers: [String]) might be more precise?
I've got a problem since my app, evidently, calls the new notification function every time the app finished launching (in AppDelegate). How do I make my newNotification()-function only being called, when it's used for a new notification and not when the app started launching?
Here's the relevant code from appDelegate (mvc = MainViewController):
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound]) { (granted, error) in
}
let generalCategory = UNNotificationCategory(identifier: "GENERAL",
actions: [],
intentIdentifiers: [],
options: .customDismissAction)
center.setNotificationCategories([generalCategory])
let content = UNMutableNotificationContent()
mvc.newNotification()
let contentText = UserDefaults.standard.string(forKey: "contentText")
content.title = NSString.localizedUserNotificationString(forKey: "The Better Life Challenge", arguments: nil)
content.body = NSString.localizedUserNotificationString(forKey: "\(contentText!)", arguments: nil)
var dateInfo = DateComponents()
dateInfo.hour = 4
dateInfo.minute = 0
let trigger = UNCalendarNotificationTrigger(dateMatching: dateInfo, repeats: true)
let request = UNNotificationRequest(identifier: "TBLC", content: content, trigger: trigger)
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
}
Appreciate your help!
You do this in method called, didRecieveRemoteNotification...this method fires when you recieve new notification, not didFinishLaunchingWithOptions..
We are using the UNUserNotification framework provided by WatchOS 3.0 to create local notification to notify user at a predefined moment. However, the notification is not shown when the watch is not being worn on the wrist. It does work well when someone is wearing it.
We cannot find this description on any documentation. Is that normal? If yes, how to help the user to avoiding missing some notifs ?
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in
// Enable or disable features based on authorization.
if granted {
let content = UNMutableNotificationContent()
content.title = title
content.body = body
content.sound = UNNotificationSound.default()
content.userInfo = userInfo
let trigger = UNTimeIntervalNotificationTrigger.init(
timeInterval: interval,
repeats: false)
let identifier = stringWithUUID()
let request = UNNotificationRequest.init(
identifier: identifier,
content: content,
trigger: trigger
)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
completion?(true, nil)
}
else {
completion?(false, error)
}
}
This is normal, Apple Watch automatically locks when you take it off your wrist and notifications go to your iPhone instead.