In my app, I'm fetching the content of camera-roll with fetchAssets(with:). To receive change messages, I've registered my observer with the photo library’s register(_:) method. My observer is comforting to the PHPhotoLibraryChangeObserver protocol. So when the library is changing, I should get notified about that. The scenario I want to support is while I'm running my app, I go to background, then open the camera app, take a picture, then go back to my app. Is it possible to get the notification of a change that occurred while my app was in background, when it comes back to foreground?
Yes you can create LocalNotificaion and trigger it when app is going in background and coming back in foreground.
func scheduleNotification(timeInter : TimeInterval) {
let content = UNMutableNotificationContent()
let userActions = "User Actions"
content.title = "Title "
content.body = "Body"
content.sound = UNNotificationSound.init(named:
content.categoryIdentifier = userActions
content.userInfo = ["MID" : RANDOM_ID, "timeInterval" : String(timeInter)]
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInter, repeats: false)
let identifier = String(timeInter)
let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
print(request.identifier)
notificationCenter.add(request) { (error) in
if let error = error {
}
}
// let snoozeAction = UNNotificationAction(identifier: "Snooze", title: "Snooze", options: [])
let deleteAction = UNNotificationAction(identifier: "Delete", title: "Delete", options: [.destructive])
let category = UNNotificationCategory(identifier: userActions, actions: [deleteAction], intentIdentifiers: [], options: [])
notificationCenter.setNotificationCategories([category])
}
Related
Actions fail to show.
And, they also fail to show with these downloaded notification demo apps
- LocalNotifications by Bart Jacobs
- RemindMe by Keith Harrison (Use Your Loaf)
- EatMoreVegetable by Brian Advent
Interestingly, I can make action button appear by doing this:
Step
1) In app, fire notification request
2) Leave app - go to Home screen
3) Notification appears without action button
4) Drag notification down causes action button to appear
Same results with simulator or device.
My demo app can be downloaded from here
https://github.com/tricarb/UNLocalDemo
func registerCategories() {
let center = UNUserNotificationCenter.current()
let actionID = Notify.actionID.rawValue
let categoryID = Notify.categoryId.rawValue
let action = UNNotificationAction(identifier: actionID, title: "Action Title", options: [.foreground])
let category = UNNotificationCategory(identifier: categoryID, actions: [action], intentIdentifiers: [])
center.setNotificationCategories([category])
}
func fireNotification() {
let content = UNMutableNotificationContent()
content.title = "Content Title"
content.body = "This is the content body"
content.categoryIdentifier = Notify.categoryId.rawValue
let timeInterval = TimeInterval(7)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: timeInterval, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error) in
if let error = error {
print(error.localizedDescription)
} else {
print("Notification will fire in", timeInterval, "seconds")
}
}
}
To get action button to show you need to swipe the notification to the left (in notification center). There you'll see three buttons: "Manage", "View", "Clear".
Select "View" and you'll get the same behavior as you have when you drag down the notification that just appeared.
How can we show the image or any attachment with local notifications as we used to show in rich notifications ?
I am receiving the silent notification and then changing it in local notification.
Yes, you can show it in the local notification also, you have to trigger local notification after you received silent push , I hope in your slient notification payload all require data is there.
Here is the code snippet
let content = UNMutableNotificationContent()
//Configure notification
content.title = "Notification Title"
content.body = "Notification Body"
content.sound = UNNotificationSound.default()
content.categoryIdentifier = "ImageNotification"
//Attach your image local path here (Document dir path)
let attachment = try! UNNotificationAttachment(identifier: "\(NSDate().timeIntervalSince1970 * 1000)", url: localURL, options: [:])
content.attachments = [attachment]
content.userInfo = ["attachmentType": "Media"]
// Create a trigger for fire a local notification
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.2, repeats: false)
let request = UNNotificationRequest(identifier: "\(NSDate().timeIntervalSince1970 * 1000)", content: content, trigger: trigger)
// Configure according to version
if #available(iOS 11.0, *) {
let contactCategory = UNNotificationCategory(identifier: content.categoryIdentifier,
actions: [],
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder: "",
options: .customDismissAction)
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.setNotificationCategories([contactCategory])
} else {
// Fallback on earlier versions
let contactCategory = UNNotificationCategory(identifier: content.categoryIdentifier, actions: [], intentIdentifiers: [], options: [])
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.setNotificationCategories([contactCategory])
}
UNUserNotificationCenter.current().add(request) {[weak self] (error) in
guard error == nil else {
return
}
}
After this implement it would be work fine, If you still facing any issue so please let me know.
There are a few articles that address this same problem, but (from what I've seen) they're all from 4 years ago and in Objective-C. I'm working with Swift 4.2.
I'm making a countdown timer app. While the app is in the background and a timer expires, I want the notification sound to keep playing until the user stops it by tapping on the notification.
So far, what I have only plays an alert sound once from the background/lockscreen.
Here is the method I am working with.
func notifications(title: String, message: String){
center.delegate = self
let restartAction = UNNotificationAction(identifier: "RESTART_ACTION", title: "Restart timer", options: UNNotificationActionOptions(rawValue: 0))
let stopAction = UNNotificationAction(identifier: "STOP_ACTION", title: "Stop", options: UNNotificationActionOptions(rawValue: 0))
let expiredCategory = UNNotificationCategory(identifier: "TIMER_EXPIRED", actions: [restartAction, stopAction], intentIdentifiers: [], options: UNNotificationCategoryOptions(rawValue: 0))
// Register the notification categories.
center.setNotificationCategories([expiredCategory])
let content = UNMutableNotificationContent()
content.title = title
content.body = message
content.categoryIdentifier = "TIMER_EXPIRED"
content.sound = UNNotificationSound(named:UNNotificationSoundName(rawValue: _currentTimer.getSoundEffect+".mp3"))
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(_currentTimer.endTime), repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
}
}
}
So, the answer I'm going settling on with this question is that there is no answer. Apple does not want third party developers playing notification sounds for longer than 30 seconds in any circumstance, even if it is to build a timer app. Their timer in the Clock app will go off until you silence it, but third party developers aren't allowed to do that.
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 created two different functions that each create a new local notification.
func scheduleLocalNotification() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Notif 1"
notificationContent.subtitle = "Local Notifications"
notificationContent.body = "hellow worlds."
// Set Category Identifier
notificationContent.categoryIdentifier = Notification.Category.tutorial
// 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))")
}
}
}
func scheduleLocalNotification2() {
// Create Notification Content
let notificationContent = UNMutableNotificationContent()
// Configure Notification Content
notificationContent.title = "Notif 2"
notificationContent.subtitle = "Local Notifications"
notificationContent.body = "hellow world + snooze"
// Set Category Identifier
notificationContent.categoryIdentifier = Notification.Category.tutorial
// 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))")
}
}
}
I want the first function to create a normal notification without any actions and the second to create a notification with action button. So I create the following function
func configureUserNotificationsCenter() {
// Configure User Notification Center
UNUserNotificationCenter.current().delegate = self
// Define Actions
let actionReadLater = UNNotificationAction(identifier: Notification.Action.readLater, title: "Read Later", options: [])
let actionShowDetails = UNNotificationAction(identifier: Notification.Action.showDetails, title: "Show Details", options: [.foreground])
let actionUnsubscribe = UNNotificationAction(identifier: Notification.Action.unsubscribe, title: "Unsubscribe", options: [.destructive, .authenticationRequired])
// Define Category
let tutorialCategory = UNNotificationCategory(identifier: Notification.Category.tutorial, actions: [actionReadLater, actionShowDetails, actionUnsubscribe], intentIdentifiers: [], options: [])
// Register Category
UNUserNotificationCenter.current().setNotificationCategories([tutorialCategory])
}
I then call the configureUserNotificationsCenter in viewdidload but this causes all my notifications to have these action buttons. I want only the notifications scheduled using the scheduleLocalNotifications2 function and the notifications with other functions should not have these action buttons. How do I go around making that?
Both methods are using a notificationContent.categoryIdentifier of Notification.Category.tutorial. This is the same category that you are specifying the buttons on, which is why it shows up for both. You need to create a second category identifier for your notification with no buttons