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
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 am trying to send local notifications from my Mac app(written in swift using Cocoa)
So far I've written this function
func scheduleNotification() {
let content = UNMutableNotificationContent()
content.title = "Test"
content.body = "This is a test"
content.sound = .default
content.badge = 1
let now = Date()
let int = timePicker.dateValue.timeIntervalSince(now)
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: int, repeats: false)
let request = UNNotificationRequest(identifier: "Test notification", content: content, trigger: trigger)
center.add(request) { (err) in
if err == nil {
print("Success")
}
}
}
But for some reason it doesn't show a banner or anything in the Notification Center. Is something wrong with my code or something else causing this? (I checked and the app has the permission to send notifications)
And also, what is the equivalent on macOS for the
UIApplication.shared.applicationBadgeNumber = 0 on iOS?
If app is on foreground, you have to use UNUserNotificationCenterDelegate.
UNUserNotificationCenter.current().delegate = self
Firstly notify that delegate in viewDidLoad.
extension ViewController: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
return completionHandler([.alert, .sound, .badge])
}
}
And after you can use delegate like that. Check this out more information this post -> Local Notifications
So, as it turns out asking for permission is mandatory in MacOS Catalina, that was all that missing.
Using iOS13.4, XCode11.4, Swift5.2,
In my current App, I successfully managed to create a Local Notification. A banner is shown when the notification occurs. The banner is shown independently of App-state (i.e. opened App running in Foreground or Background or even if the App is completely closed). So far so good :)
Now my question: Can you disable App-opening mechanism when the user presses the Notification Banner ?
Currently, I am using the UNUserNotificationCenterDelegate's Delegate methods to complete the notification (i.e. run some custom code when the user presses the banner). (see code-snippet below)
However, I do not want the App to necessarily open up for doing the completion work ! This could be perfectly done in the background for better customer experience.
Is it possible to run some code when the banner gets pressed but do this without App opening ? And if yes, how ?
Here is the code snippet:
import UIKit
class MyViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let content = UNMutableNotificationContent()
content.title = "My Notification Title"
content.categoryIdentifier = UUID().uuidString
var notificationIdentifier = "23224-23134-234234"
var notificationDate = Date(timeInterval: 30, since: Date())
let notificationTriggerKind = Calendar.current.dateComponents([.day, .month, .year, .hour, .minute, .second], from: notificationDate)
let notificationTrigger = UNCalendarNotificationTrigger(dateMatching: notificationTriggerKind, repeats: false)
let notificationRequest = UNNotificationRequest(identifier: notificationIdentifier, content: content, trigger: notificationTrigger)
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.delegate = self
notificationCenter.add(notificationRequest) {(error) in if let error = error { print("error: \(error)") } }
}
}
extension MyViewController: UNUserNotificationCenterDelegate {
// kicks in when App is running in Foreground (without user interaction)
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// ...do your custom code...
completionHandler([.alert, .sound])
}
// kicks in when App is running in Foreground or Background
// (AND App is open) AND user interacts with notification
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse, withCompletionHandler
completionHandler: #escaping () -> Void) {
// ... do your custom code ....
return completionHandler()
}
}
i'm trying to send a local notification following this tutorial:
https://useyourloaf.com/blog/local-notifications-with-ios-10/
I added this code to my viewDidLoad():
let center = UNUserNotificationCenter.current()
let options: UNAuthorizationOptions = [.alert, .sound];
center.requestAuthorization(options: options) {
(granted, error) in
if !granted {
print("Something went wrong")
}
}
let content = UNMutableNotificationContent()
content.title = "Don't forget"
content.body = "Buy some milk"
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5,
repeats: false)
let identifier = "UYLLocalNotification"
let request = UNNotificationRequest(identifier: identifier,
content: content, trigger: trigger)
center.add(request, withCompletionHandler: { (error) in
if let error = error {
print("error")
}
})
but 5 seconds pass without any notification shown. the CompletionHandler is called with error being nil
If you want the notification when app is in foreground, then you'll have to add some more code into your controller,
Add the following line at the end of viewDidLoad()
center.delegate = self
This makes your ViewController the delegate to which the notification can callback when it hits.
Confirm your view controller to the delegate, (Add UNUserNotificationCenterDelegate)
class ViewController: UIViewController, UNUserNotificationCenterDelegate {
Now you can write callback methods in your ViewController.
Write the callback to present your notification, you can add this method right after viewDidLoad()
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.alert, .badge, .sound])
}
This will make your notification to popup even if the app is in foreground.
NOTE: It is highly recommended that you register your notifications (Local/Remote) in AppDelegate rather than ViewController.