Swift UNUserNotification does not trigger sound - ios

This is my code for UNUserNotification
func scheduleNotification() {
UNUserNotificationCenter.current().getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .notDetermined:
self.requestAuthorization(completionHandler: { (success) in
guard success else { return }
// Schedule Local Notification
self.scheduleLocalNotification()
})
case .authorized:
// Schedule Local Notification
self.scheduleLocalNotification()
case .denied:
print("Application Not Allowed to Display Notifications")
}
}
}
private func scheduleLocalNotification() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Hello"
notificationContent.body = ""
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10.0, repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: id, content: notificationContent, trigger: notificationTrigger)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}
private func requestAuthorization(completionHandler: #escaping (_ success: Bool) -> ()) {
// Request Authorization
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
completionHandler(success)
}
}
It schedules the notification 10 seconds after the call and it works, the notification is presented on the lock screen, the problem is that it does not trigger any sound/vibration.
Upon request I'm setting these options [.alert, .sound, .badge], what am I missing?
p.s. I am not willing to set a custom sound, the default one is enough

You are missing the critical element that will play the sound:
notificationContent.sound = UNNotificationSound.default()
Including UNMutableNotificationContent should solve your issue.

Related

Implementing Background Capabilities on Swift

I recently just finished an app that basically has an Observer for a Firebase Database, and when a certain attribute changes, sends a banner type notification.
The application works completely, but when I had the app in the background while using the phone, I realized that it doesn't run any code, or send notifications.
How can I implement both having the Observer listening for any changes from the Database in the background, as well as send a notification?
Here is the Notification Authorization Request function:
func requestNotificationAuthorization() {
let authOptions = UNAuthorizationOptions.init(arrayLiteral: .alert, .badge, .sound)
self.userNotificationCenter.requestAuthorization(options: authOptions) { (success, error) in
if let error = error {
print("Error: ", error)
}}}
The Notification Center function:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
completionHandler()
}
And the Send Notification function:
func sendNotification() {
// Create new notifcation content instance
let notificationContent = UNMutableNotificationContent()
// Add the content to the notification content
notificationContent.title = "P2P Tracker"
notificationContent.body = (PriceTimeDate ?? "")
print(notificationContent.body)
notificationContent.badge = NSNumber(value: 1)
// Add an attachment to the notification content
if let url = Bundle.main.url(forResource: "dune",
withExtension: "png") {
if let attachment = try? UNNotificationAttachment(identifier: "dune",
url: url,
options: nil) {
notificationContent.attachments = [attachment]
}
}
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3,
repeats: false)
let request = UNNotificationRequest(identifier: "testNotification",
content: notificationContent,
trigger: trigger)
userNotificationCenter.add(request) { (error) in
if let error = error {
print("Notification Error: ", error)
}
}
}

Local Notification content going into a loop in iOS

I'm trying to implement local notifications within my app. The idea is that the user is sent a notification every day at 9:00 a.m. with a different quote, but I encountered a bug where the same content of the notification is always shown, i.e. the same quote is repeated endlessly. How could I fix it? This is the code I'm using, and I tried to use a UUID for every notification that is sent, but it didn't bring improvements.
let notificationCenter = UNUserNotificationCenter.current()
let options: UNAuthorizationOptions = [.alert, .sound]
notificationCenter.requestAuthorization(options: options) {
(didAllow, error) in
if !didAllow {
print("User has declined notifications")
}
}
notificationCenter.getNotificationSettings { (settings) in
if settings.authorizationStatus != .authorized {
print("Notifications not allowed")
}
}
let randomArrayNotificationQuote = Int(arc4random_uniform(UInt32(myQuotes.count)))
let randomArrayNotificationTitle = Int(arc4random_uniform(UInt32(myTitle.count)))
let content = UNMutableNotificationContent()
content.title = "\(myTitle[randomArrayNotificationTitle])"
content.body = "\(myQuotes[randomArrayNotificationQuote])"
content.sound = UNNotificationSound.default
content.categoryIdentifier = "com.giovannifilippini.philo"
// Deliver the notification
var dateComponents = DateComponents()
dateComponents.hour = 9
dateComponents.minute = 00
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let uuid = UUID().uuidString
let request = UNNotificationRequest.init(identifier: uuid, content: content, trigger: trigger)
notificationCenter.add(request) { (error) in
if error != nil {
print("add NotificationRequest succeeded!")
notificationCenter.removePendingNotificationRequests(withIdentifiers: [uuid])
}
}
The issue here is the trigger has the repeats set to true
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
You would need to set it to false and re run this method every time you want to schedule different notification (different content)
In order to receive the Notification while the app is in the foreground you need to implement the willPresent method from the UNUserNotificationCenterDelegate
Here is a simple example:
class ViewController: UIViewController {
private let userNotificaionCenter = UNUserNotificationCenter.current()
override func viewDidLoad() {
super.viewDidLoad()
// 1. Assign the delegate
userNotificaionCenter.delegate = self
scheduleNotification()
}
func scheduleNotification() {
// Same notification logic that you have
}
}
// 2. Implement the UNUserNotificationCenterDelegate
extension ViewController: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// This will allow the app to receive alerts and sound while in the foreground
completionHandler([.alert, .sound])
}
}

How to schedule Notifications in Swift

I am trying to schedule notifications in my project. I don't get any errors or runtime crashes, however for some reason I don't get any notifications on the simulator when scheduling. I am not sure where exactly I am going wrong, as I have been successful in doing so in a previous project.
Does anyone have any suggestions ?
import UserNotifications
func addNotification(title: String, category: String, UI: String, date: Date) {
// Remove Notification
removeNotifcation(UI: UI)
// Create Notification
// iOS 10 Notification
if #available(iOS 10.0, *) {
let notif = UNMutableNotificationContent()
notif.title = title
notif.subtitle = "Reminder for \(title)"
notif.body = "Your Reminder for \(title) set for \(date)"
notif.sound = UNNotificationSound.default()
notif.categoryIdentifier = UI
let today = Date()
let interval = date.timeIntervalSince(today as Date)
let notifTrigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: false)
let request = UNNotificationRequest(identifier: title, content: notif, trigger: notifTrigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: { error in
if error != nil {
print(error as Any)
// completion(Success: false)
} else {
//completion(Sucess: true)
}
})
} else {
let newNotification:UILocalNotification = UILocalNotification()
newNotification.category = category
newNotification.userInfo = [ "UUID" : UI]
newNotification.alertBody = "Your reminder for \(title)"
newNotification.fireDate = date
//notification.repeatInterval = nil
newNotification.soundName = UILocalNotificationDefaultSoundName
UIApplication.shared.scheduleLocalNotification(newNotification)
}
}
func removeNotifcation(UI: String) {
//Remove Notif
//iOS 10 Notification
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().removePendingNotificationRequests(withIdentifiers: [UI])
} else {
//Remove Notif
let app:UIApplication = UIApplication.shared
for oneEvent in app.scheduledLocalNotifications! {
let notification = oneEvent as UILocalNotification
let userInfoCurrent = notification.userInfo!
let uuid = userInfoCurrent["UUID"] as! String
if uuid == UI {
//Cancelling local notification
app.cancelLocalNotification(notification)
break;
}
}
}
}
This is how I am calling the methods
dataManager.addNotification(title: "String", category: "001", UI: uuid, date: datePicker.date)
Notifications don't appear when app is in foreground only if you implement willPresent delegate method and because of
let today = Date()
this date makes it triggers when you run it , so add a time interval and send app to background and you'll see it , plus make sure you request a permission for it in AppDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
print("granted: (\(granted)")
}
return true
}
Also you can have a look to this tutorial
//
Edit : to verify it triggers anyway implement this
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("handling notifications with the TestIdentifier Identifier")
completionHandler()
}
and set the delegate to the VC
UNUserNotificationCenter.current().delegate = self

iOS slow local notifications scheduling

I have a problem with local notifications scheduling (I'm using all available slots - 64). Main problem that it took a lot of time, on slow devices (iPhone 5C) up to 20 seconds !
Here how I'm doing this:
let notificationCenter = UNUserNotificationCenter.current()
for notification in unNotifications { //64 notifications
notificationCenter.add(notification) { _ in
//do nothing here
}
}
I didn't find any bunch method to schedule all notifications with one method call. What could be wrong ?
Simply follow the steps you will get what you are missing.
Request Notification
// Request Notification Settings
UNUserNotificationCenter.current().getNotificationSettings { (notificationSettings) in
switch notificationSettings.authorizationStatus {
case .notDetermined:
self.requestAuthorization(completionHandler: { (success) in
guard success else { return }
// Schedule Local Notification
})
case .authorized:
// Schedule Local Notification
case .denied:
print("Application Not Allowed to Display Notifications")
}
}
Requesting Authorization
// MARK: - Private Methods
private func requestAuthorization(completionHandler: #escaping (_ success: Bool) -> ()) {
// Request Authorization
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (success, error) in
if let error = error {
print("Request Authorization Failed (\(error), \(error.localizedDescription))")
}
completionHandler(success)
}
}
Scheduling a Notification
private func scheduleLocalNotification() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Cocoacasts"
notificationContent.subtitle = "Local Notifications"
notificationContent.body = "In this tutorial, you learn how to schedule local notifications with the User Notifications framework."
// Add Trigger
let notificationTrigger = UNTimeIntervalNotificationTrigger(timeInterval: 10.0, repeats: false)
// Create Notification Request
let notificationRequest = UNNotificationRequest(identifier: "cocoacasts_local_notification", content: notificationContent, trigger: notificationTrigger)
// Add Request to User Notification Center
UNUserNotificationCenter.current().add(notificationRequest) { (error) in
if let error = error {
print("Unable to Add Notification Request (\(error), \(error.localizedDescription))")
}
}
}
Implementing the Delegate Protocol
// Configure User Notification Center
UNUserNotificationCenter.current().delegate = self
extension ViewController: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert])
}
}
While testing result is:
Reference: https://cocoacasts.com/local-notifications-with-the-user-notifications-framework

Local Notifications make sound but do not display (Swift)

I am trying to create a local notification for my app using Apple's UNUserNotificationCenter.
Here is my code:
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = task.name
content.body = task.notes
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: task.UUID, content: content, trigger: trigger)
center.add(request) { (error:Error?) in
if let theError = error {
print("Notification scheduling error: \(error)")
}else{
print("Notification was scheduled successfully")
}
}
Access Request:
let center = UNUserNotificationCenter.current()
//request notification access
let options: UNAuthorizationOptions = [.alert, .sound]
center.requestAuthorization(options: options) { (granted, error) in
if !granted {
print("Notification access was denied")
}
}
After 5 seconds the app makes the Default sound but does not show the alert content. I am trying both with the app in the foreground and in the background.
I had the same problem.
If your content body is blank ie(content.body == "") then you won't get a notification even if you do have a title.
So the solution is to make sure that your content body is not an empty string.
Add this Protocoal UNUserNotificationCenterDelegate.
and add this delegate into your controller. and dont forget to set delegate.
UNUserNotificationCenter.current().delegate = self
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("Notification being triggered")
//You can either present alert ,sound or increase badge while the app is in foreground too with ios 10
//to distinguish between notifications
if notification.request.identifier == "yourrequestid"{
completionHandler( [.alert,.sound,.badge])
}
}
Add this code into didFinishLaunchingWithOption in AppDelegate.swift file
let center = UNUserNotificationCenter.current()
center.requestAuthorization(options: [.alert, .sound])
{ (granted, error) in
// Enable or disable features based on authorization.
}

Resources