I have this:
import SwiftUI
import UserNotifications
struct ContentView: View {
var body: some View {
VStack {
Button("Request Permission") {
RequestNotificationsAccess()
}
Button("Schedule Notification") {
ScheduleNotification()
}
}
}
}
func RequestNotificationsAccess() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
print("All set!")
} else if let error = error {
print(error.localizedDescription)
}
}
}
func ScheduleNotification() {
let content = UNMutableNotificationContent()
content.title = "Title:"
content.subtitle = "some text"
content.sound = UNNotificationSound.default
// show this notification five seconds from now
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
// choose a random identifier
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
// add our notification request
UNUserNotificationCenter.current().add(request)
}
It works great but when I click multiple times on the button, the notification appears multiple times, how can I track if it was fired already and if so, don't display anything?
Thanks
ok, to make the previous notification not display, try something like this before you schedule another notification:
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
or keep track of the id and use
removeDeliveredNotifications(withIdentifiers:)"
Related
I want to develop a command line tool for notifications, like https://github.com/julienXX/terminal-notifier and
use new UserNotification API
But now the program is throw a exception:
Optional(Error Domain=UNErrorDomain Code=1 "Notifications are not allowed for this application" UserInfo={NSLocalizedDescription=Notifications are not allowed for this application})
I don't know under what circumstances the Notification Center will throw this exception, and I would like to ask what configuration needs to be added to use the Notification Center in the command line tool.
My code:
import Cocoa
import UserNotifications
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
let content = UNMutableNotificationContent()
content.title = "title"
content.body = "body"
content.userInfo = ["method": "new"]
content.sound = UNNotificationSound.default
content.categoryIdentifier = "NOTIFICATION"
let testCategory = UNNotificationCategory(identifier: "NOTIFICATION",
actions: [],
intentIdentifiers: [],
hiddenPreviewsBodyPlaceholder: "",
options: .customDismissAction)
let request = UNNotificationRequest(identifier: "NOTIFICATION_REQUEST",
content: content,
trigger: nil)
// Schedule the request with the system.
let center = UNUserNotificationCenter.current()
center.setNotificationCategories([testCategory])
center.add(request) { (error) in
if error != nil {
// Handle any errors.
print(error)
}
}
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {
return true
}
}
let app = NSApplication.shared
let appDelegate = AppDelegate()
app.delegate = appDelegate
app.run()
I am trying to make it so a notification asking the user to subscribe will not appear anymore when the user is subscribed to my app, below i s my notifications class i am implementing, just having a hard time figuring out how to add code in to null out the alert when they are actually subscribed.
import Foundation
import UserNotifications
class Notifications: NSObject, UNUserNotificationCenterDelegate {
func notificationRequest() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
if success {
print("All set!")
} else if let error = error {
print(error.localizedDescription)
}
}
}
func addNotification() {
print("foi")
let content = UNMutableNotificationContent()
content.title = "WARNING: Safari at risk! ⚠️"
content.subtitle = "Tap here to secure your device!"
content.sound = UNNotificationSound.default
// show this notification 3 days from now 259200
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 259200, repeats: true)
// choose a random identifier
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
// add our notification request
UNUserNotificationCenter.current().add(request)
}
func clearNotification() {
UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
}
}
I noob in development application on OSX. I want to create app with Share extension. After content loading I want to show Notification, but I getting error "Notifications are not allowed for this application". I don't understand why requestAuthorization method not show dialog windows with permission, and how I can allow application to send notifications.
This is my code:
import Cocoa
import UserNotifications
class ShareViewController: NSViewController {
override func loadView() {
self.view = NSView()
// Insert code here to customize the view
let item = self.extensionContext!.inputItems[0] as! NSExtensionItem
NSLog("Attachment = %#", item.attachments! as NSArray)
showNotification()
let outputItem = NSExtensionItem()
let outputItems = [outputItem]
self.extensionContext!.completeRequest(returningItems: outputItems, completionHandler: nil)
}
func showNotification() -> Void {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.requestAuthorization(options: [.alert, .badge]) {
(granted, error) in
if granted {
print("Yay!")
} else {
print("D'oh") // Print this, not authorized
}
}
let content = UNMutableNotificationContent()
content.title = "Hello"
content.body = "This is example"
content.sound = UNNotificationSound.default
content.badge = 1
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
notificationCenter.add(request) { (error : Error?) in
if let theError = error {
print(theError) // Print Domain=UNErrorDomain Code=1 "Notifications are not allowed for this application"
}
}
}
}
I don't see anywhere in the documentation that says you can't schedule new Local Notifications from an extension. I do however see an apple support ticket where someone had to deal with this issue, as do I.
Basically this failure is a race-condition. The key is to not call the contentHandler of this extension method:
override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: #escaping (UNNotificationContent) -> Void) {
until after the completion handler of
notificationCenter.add(request: UNNotificationRequest>, withCompletionHandler: ((Error?) -> Void)
is called. It worked for me. Make sense?
Apple does't allow send Notifications from Share extensions.
Documentation
I have a notification function that works, see below. But I want to add an additional option, for example starting a timer, or set a flag, that is triggered by the notification event. How do I do it?
func scheduleNotification() {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Late wake up call"
// Configure the trigger for a 10pm wakeup.
var dateInfo = DateComponents()
dateInfo.hour = 22
dateInfo.minute = 0
let trigger = UNCalendarNotificationTrigger(dateMatching: dateInfo, repeats: true)
// Create the request object.
let request = UNNotificationRequest(identifier: "TimesUp", content: content, trigger: trigger)
center.add(request) { (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
}
}
}
From example, once the notification is triggered, I want to start a timer, or set a flag = true, ...
I do not know how to implement the function so that notifications come one by one from the data array. Here is my function that displays only one,last notification :
func addNotificationWithTimeIntervalTrigger(title :String){
let content = UNMutableNotificationContent()
content.title = title
content.subtitle = "Subtitle"
content.body = "Body"
//content.badge = 1
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)
let reguest = UNNotificationRequest(identifier: "timeInterval", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(reguest) { (error) in
}
}
Here I just pass the data from my tableView :
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch indexPath.row {
case 0:
UserNotificationManager.shared.addNotificationWithTimeIntervalTrigger(title:"aaa")
default: break
}
My notification :
How to make the notifications go one by one from the array?
Make sure that every scheduled notification has a different identifier , otherwise the new one will replace the old
let reguest = UNNotificationRequest(identifier: "timeInterval", content: content, trigger: trigger)
This could be achieved by using the indexPath.row to get an object from your data model. You have not shared your data model, but an array is a useful way to store your objects for situations like this.
With some changes, your custom function could look like this. You can now pass an integer index to get the correct object from your model.
func addNotificationWithTimeIntervalTrigger(title: String, index: Int) {
guard let thisObject = yourDataModelArray[index] as? YourObjectType else { return }
let content = UNMutableNotificationContent()
content.title = title // This could be taken from data model instead
content.subtitle = thisObject.subtitle
content.body = thisObject.body
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 3, repeats: false)
let reguest = UNNotificationRequest(identifier: "timeInterval", content: content, trigger: trigger)
UNUserNotificationCenter.current().add(reguest) { (error) in
if let error = error {
// Error handling
}
}
}
Then you could call it like this. No switch statement needed as it pulls data from your data model based on the indexPath.row. Note that you could also store the titles in your data model, meaning you would not have to pass this as an argument.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
UserNotificationManager.shared.addNotificationWithTimeIntervalTrigger(title:"Custom title", index: indexPath.row)
}
Try This Separate File created for local Notifications
import Foundation
import UIKit
import UserNotifications
struct NotificationHandlerStruct {
static var notifyTimer : Timer?
}
class LocalNotificationHandler: NSObject, UNUserNotificationCenterDelegate
{
static var shared = LocalNotificationHandler()
//MARK: Schedule Notification
func scheduleNotification(Title title: String, Subtitle subtitle: String, BodyMessage body: String, AlertContent contentRx:[AnyHashable:Any]) {
/// Remove Previous Displayed Notification in case if you need
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ["gruveoCall"])
let content = UNMutableNotificationContent()
//adding title, subtitle, body and badge
content.title = title
content.subtitle = subtitle
content.sound = UNNotificationSound.default()
content.body = body
content.badge = 0
content.userInfo = contentRx
//getting the notification trigger
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.01, repeats: false)
//getting the notification request
let request = UNNotificationRequest(identifier: "gruveoCall", content: content, trigger: trigger)
//adding the notification to notification center
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
/// Comment Code below if you do not want to repeat same notification again after some interval of time
if NotificationHandlerStruct.notifyTimer == nil {
NotificationHandlerStruct.notifyTimer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { (timer) in
self.sendNotification(NotificationContent: content)
})
}
else{
NotificationHandlerStruct.notifyTimer?.invalidate()
NotificationHandlerStruct.notifyTimer = nil
}
}
//MARK: Repeat Notification
func sendNotification(NotificationContent content: UNMutableNotificationContent) {
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: ["gruveoCall"])
//getting the notification trigger
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.01, repeats: false)
//getting the notification request
let request = UNNotificationRequest(identifier: "gruveoCall", content: content, trigger: trigger)
//adding the notification to notification center
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
//MARK: Stop Timer
func stopTimer() {
if NotificationHandlerStruct.notifyTimer != nil {
NotificationHandlerStruct.notifyTimer?.invalidate()
NotificationHandlerStruct.notifyTimer = nil
}
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
//displaying the ios local notification when app is in foreground
completionHandler([.alert, .badge, .sound])
}
}
Usage
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
LocalNotificationHandler.shared.scheduleNotification(Title: self.providerListArray![indexPath.row], Subtitle: "My Subtitle", BodyMessage: "Some Message", AlertContent: ["aps":["data":"your Content"]])
}