I have a local notification and I added an action to it. How should I do so that when the action is tapped, the local notification is fired again after 15 minutes?
Here is the code and the extension so that the notification can be showed using an UIImage:
extension UNNotificationAttachment {
static func create(identifier: String, image: UIImage, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
do {
try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
let imageFileIdentifier = identifier+".png"
let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
guard let imageData = UIImagePNGRepresentation(image) else {
return nil
}
try imageData.write(to: fileURL)
let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL, options: options)
return imageAttachment
} catch {
print("error " + error.localizedDescription)
}
return nil
}
}
func scheduleNotification() {
removeNotification()
if shouldRemind && dueDate > Date() {
let content = UNMutableNotificationContent()
content.title = "Reminder:"
content.body = text
content.sound = UNNotificationSound.default()
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents([.month, .day, .hour, .minute], from: dueDate)
let trigger = UNCalendarNotificationTrigger(dateMatching: components, repeats: false)
let identifier = ProcessInfo.processInfo.globallyUniqueString
if let attachment = UNNotificationAttachment.create(identifier: identifier, image: notificationImage, options: nil) {
content.attachments = [attachment]
}
let action = UNNotificationAction(identifier: "remindLater", title: "Remind me later", options: [])
let category = UNNotificationCategory(identifier: "category", actions: [action], intentIdentifiers: [], options: [])
UNUserNotificationCenter.current().setNotificationCategories([category])
content.categoryIdentifier = "category"
let request = UNNotificationRequest(identifier: "\(itemID)", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request)
}
}
Just call a modified version scheduleNotification again in the action handler when the user activates the action. I would definitely create a function variable as a TimeInterval or a boolean which determines the trigger time of the notification.
Related
I implemented chat using MessageKit and Firebase and was wondering how to implement notifications whenever the user receives a message, I have set up my permissions but I'm having trouble figuring out knowing when a new message is sent. Any ideas would be appreciated.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let content = UNMutableNotificationContent()
databaseListener = channelRef?.order(by:"time").addSnapshotListener() { (querySnapshot, error) in
if let error = error {
print(error)
return
}
querySnapshot?.documentChanges.forEach() { diff in
if diff.type == .added {
let snapshot = diff.document
let id = snapshot.documentID
let senderId = snapshot["senderId"] as! String
let senderName = snapshot["senderName"] as! String
let text = snapshot["text"] as! String
let timestamp = snapshot["time"] as! Timestamp
let date = sentTimestamp.dateValue()
let sender = Sender(id: senderId, name: senderName)
let message = ChatMessage(sender: sender, messageId: id, sentDate: date, message: text)
self.messagesList.append(message)
// Notification
content.title = "New message"
content.body = "Tap to respond"
content.categoryIdentifier = AppDelegate.CATEGORY_IDENTIFIER
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 2, repeats: false)
let request = UNNotificationRequest(identifier: ChatMessagesViewController.NOTIFICATION_IDENTIFIER, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
self.messagesCollectionView.insertSections([self.messagesList.count-1])
}
}
}
}
Hello I am making an alarm app and I am trying to play audio when the user receives the local notification. I keep all my local notification functions and management in a swift file titled NotificationPublisher. It works when the user has the app in the foreground because the willPresent() function gets called, however I am trying to make it work in the background/phone is closed.
Is there a function that gets called when a local notification is presented in background and not just the foreground?
If not am I tackling this feature wrong.
Here is my sendNotification function where I take in my alarms and schedule the local notifications. (In my NotificationPublisher.swift)
func sendNotification(alarm : Alarm, badge: Int?) {
let notificationContent = UNMutableNotificationContent()
notificationContent.title = alarm.alarmName
notificationContent.subtitle = alarm.alarmTime + " " + alarm.alarmPeriod
notificationContent.body = "Click here to open the app and click the solve button!"
if let badge = badge {
var currentBadgeCount = UIApplication.shared.applicationIconBadgeNumber
currentBadgeCount += badge
notificationContent.badge = NSNumber(integerLiteral: currentBadgeCount)
}
notificationContent.sound = UNNotificationSound.default
UNUserNotificationCenter.current().delegate = self
var hour = ""
if(alarm.alarmTime.count == 4){
hour = String(alarm.alarmTime.prefix(1))
} else {
hour = String(alarm.alarmTime.prefix(2))
}
let minute = String(alarm.alarmTime.suffix(2))
var intHour = Int(hour)!
if(alarm.alarmPeriod == "PM" && intHour != 12){
intHour += 12
} else if(alarm.alarmPeriod == "AM" && intHour == 12) {
intHour = 0
}
var dateComponents = DateComponents()
if(alarm.alarmDays.filter{$0}.count == 0) {
dateComponents.hour = intHour
dateComponents.minute = Int(minute)!
dateComponents.timeZone = .current
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true) // Repeating Alarm
let request = UNNotificationRequest(identifier: alarm.alarmKey, content: notificationContent, trigger: trigger) // replace trigger with delaytimetrigger and vice versa for exact time
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print(error.localizedDescription)
}
}
} else {
dateComponents.hour = intHour
dateComponents.minute = Int(minute)!
dateComponents.timeZone = .current
let days = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"]
for i in alarm.alarmDays.enumerated() {
if(i.element){
dateComponents.weekday = i.offset + 1
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
let request = UNNotificationRequest(identifier: alarm.alarmKey + days[i.offset], content: notificationContent, trigger: trigger)
UNUserNotificationCenter.current().add(request) { error in
if let error = error {
print(error.localizedDescription)
}
}
}
}
}
}
Here is the audio function that is in my ViewController.swift that I am calling from my willPresent() function.
func alarmSound() {
print("alarm sound was called")
if let player = player, player.isPlaying {
player.stop()
} else {
let urlString = Bundle.main.path(forResource: "buzzer", ofType: "mp3")
do {
try AVAudioSession.sharedInstance().setMode(.default)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
guard let urlString = urlString else { return }
player = try AVAudioPlayer(contentsOf: URL(fileURLWithPath: urlString))
guard let player = player else { return }
player.numberOfLoops = -1
player.play()
} catch {
print(error)
}
}
}
I am not sure if this will work, but I know the setting sound property will change the sound for your notification. Please check the below link and share your feedback.
https://smashswift.com/create-custom-notification-sound/#:~:text=Scheduling%20local%20notification%20you%20need,of%20UNNotificationSound%20to%20sound%20field.&text=The%20filename%20has%20to%20match,the%20same%20with%20Push%20Notification.
The expected behavior for my application is to allow multiple, stacked applications and the user should be able to interact with each notification serperately, however when a user clears one notification or uses one of the action buttons on the notification all of my apps notifications are removed from the lock screen. Is there a way to not clear all notifications after one of them is interacted with?
Notification creator function:
func sendNotification (customerName:String) {
let durationString = String(durationDetected!)
let content = UNMutableNotificationContent()
content.title = "Duration: \(durationString)"
content.subtitle = "Customer Name: \(customerName)"
//content.body = "Don't forget to bring coffee."
//content.badge = 1
let customerFacing = UNNotificationAction(identifier:"yes",
title:"Customer Facing",options:[])
let notCustomerFacing = UNNotificationAction(identifier:
"no", title: "Not Customer Facing", options: [])
/*let changeTime = UNTextInputNotificationAction(identifier:
"changeTime", title: "Modify Time", options: [])
let changeName = UNTextInputNotificationAction(identifier:
"changeName", title: "Modify Customer Name", options: [])*/
let category = UNNotificationCategory(identifier: "actionCategory",
actions: [customerFacing, notCustomerFacing],
intentIdentifiers: [], options: [])
content.categoryIdentifier = "actionCategory"
UNUserNotificationCenter.current().setNotificationCategories(
[category])
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3,
repeats: false)
let eventArrayIndex = LocationService.locationInstance.eventLogArray.count - 1
let requestIdentifier = String(eventArrayIndex)
let request = UNNotificationRequest(identifier: requestIdentifier,
content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request,
withCompletionHandler: { (error) in
// Handle error
})
}
response delegate:
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive
response: UNNotificationResponse, withCompletionHandler completionHandler:
#escaping () -> Void) {
let eventIndexString = response.notification.request.identifier
eventIndex = Int(eventIndexString)!
print("Index \(eventIndex)")
switch response.actionIdentifier {
case "yes":
print("Received")
LocationService.locationInstance.eventLogArray[eventIndex].status = "customerFacing"
let currentID = LocationService.locationInstance.eventLogArray[eventIndex].uniqueID
for (index,element) in LocationService.locationInstance.missedEventArray.enumerated() {
if element.uniqueID == currentID {LocationService.locationInstance.missedEventArray.remove(at: index)}
}
self.commitEventToDatabase(eventObject: LocationService.locationInstance.eventLogArray[eventIndex])
//self.eventLog.reloadData()
case "no":
print(LocationService.locationInstance.eventLogArray.count)
print("WHHHAT")
let currentID = LocationService.locationInstance.eventLogArray[eventIndex].uniqueID
for (index,element) in LocationService.locationInstance.missedEventArray.enumerated() {
if element.uniqueID == currentID {LocationService.locationInstance.missedEventArray.remove(at: index)}
}
LocationService.locationInstance.eventLogArray[eventIndex].status = "notCustomerFacing"
print(LocationService.locationInstance.eventLogArray.count)
//self.eventLog.reloadData()
default:
break
}
completionHandler()
}
I've set the user notification. They got deliver well but the badge on the app icon is always one.
Here's my code:
let center = UNUserNotificationCenter.current()
let options: UNAuthorizationOptions = [.alert, .badge, .sound];
center.requestAuthorization(options: options) {
(granted, error) in
if !granted {
// ask for permission
}
}
When the use click the button i schedule the notif:
#IBAction func saveBtnPressed(sender: UIButton) {
scheduleNotif()
}
Here's the scheduleNotif function
func scheduleNotif() {
let dateformatter = DateFormatter()
dateformatter.dateStyle = DateFormatter.Style.medium
dateformatter.timeStyle = DateFormatter.Style.short
let dateFromString = dateformatter.date(from: selectDateTextField.text!)
let fireDateOfNotification: Date = dateFromString!
//Notif are enabled
let content = UNMutableNotificationContent()
content.title = notifTitleTextField.text!
content.body = notifNoteTextView.text
content.sound = UNNotificationSound.default()
content.badge = UIApplication.shared.applicationIconBadgeNumber + 1 as NSNumber
var trigger: UNCalendarNotificationTrigger
var triggerDate = DateComponents()
trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: false)
let titleNospace = notifTitleTextField.text?.replacingOccurrences(of: " ", with: "")
var 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)
}
})
}
Any idea why the badge will always display one and never increment as the notifications are delivered?
Thank you
I think you need to increment applicationIconBadgeNumber. So replace
content.badge = UIApplication.shared.applicationIconBadgeNumber + 1 as NSNumber
By:
UIApplication.shared.applicationIconBadgeNumber += 1
content.badge = UIApplication.shared.applicationIconBadgeNumber as NSNumber
I have issue with notification attachment, when I add attachments to Notification it will not working, but when I delete the code for attachments it worked probley with no issue
can anyone try to fix this issue.
here is the function for notification in AppDelegate:
#available(iOS 10.0, *)
func scheduleNotification(currentGame: games) {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let calendar = Calendar(identifier: .gregorian)
let comp = calendar.dateComponents(in:.current, from: dateFormatter.date(from: currentGame.gameDate)!)
let newComponents = DateComponents(calendar: calendar ,year: comp.year ,month: comp.month , day: comp.day, hour: comp.hour, minute: comp.minute ,second: comp.second)
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: false)
let content = UNMutableNotificationContent()
content.title = NSLocalizedString("NOTIFICATION_TITLE", comment: "Game Released")
content.body = "\(currentGame.gameName) Released ✌🏻"
content.sound = UNNotificationSound.default()
content.badge = 1
if let url = NSURL(string: "http://www.ya-techno.com/gamesImage/\(currentGame.gameImage)"){
do {
let attachment = try UNNotificationAttachment(identifier: "image", url: url as URL, options: nil)
content.attachments = [attachment]
} catch {
print("The attachment was not loaded.")
}
}
let request = UNNotificationRequest(identifier:currentGame.gameID, content: content, trigger: trigger)
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().add(request) {(error) in
if let error = error {
print("error: \(error)")
}
}
}
#available(iOS 10.0, *)
func removeAllPendingNotificationRequests(){
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
}
and here is the image from console:
Try the below code
func scheduleNotification(at date: Date) {
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents(in: .current, from: date)
let newComponents = DateComponents(calendar: calendar, timeZone: .current, month: components.month, day: components.day, hour: components.hour, minute: components.minute)
let trigger = UNCalendarNotificationTrigger(dateMatching: newComponents, repeats: false)
let identifier = ProcessInfo.processInfo.globallyUniqueString
let content = UNMutableNotificationContent()
content.title = "Hello"
content.body = "World"
content.sound = UNNotificationSound.default()
let myImage: UIImage = UIImage(named: "logo.png")!
if let attachment = UNNotificationAttachment.create(identifier: identifier, image: myImage, options: nil) {
// where myImage is any UIImage that follows the
content.attachments = [attachment]
}
let request = UNNotificationRequest.init(identifier: identifier, content: content, trigger: trigger)
UNUserNotificationCenter.current().add(request) { (error) in
// handle error
}
}
Use the below extension to get the image, which you added in your project.
extension UNNotificationAttachment {
/// Save the image to disk
static func create(identifier: String, image: UIImage, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
do {
try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
let imageFileIdentifier = identifier+".png"
let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
guard let imageData = UIImagePNGRepresentation(image) else {
return nil
}
try imageData.write(to: fileURL)
let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL, options: options)
return imageAttachment
} catch {
print("error " + error.localizedDescription)
}
return nil
}
}