SWIFT send local notification - swift

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.

Related

Why my didRecive and willPresent aren’t working(action buttons do nothing)?

I want to make an actionable notification. It appears only if my app is closed. When I press action button nothing happening
My class of notification
class Notfication : NSObject, UNUserNotificationCenterDelegate {
func request(answer : rope, RopesBas : RopesBase){
let taskCategory = UNNotificationCategory(identifier: "task", actions: [UNNotificationAction(identifier: "done", title: "Done")], intentIdentifiers: [])
UNUserNotificationCenter.current().setNotificationCategories([taskCategory])
print("0 stage")
let content = UNMutableNotificationContent()
content.title = answer.name
content.sound =
UNNotificationSound.default
content.categoryIdentifier = "task"
content.userInfo=["name" : answer.name]
print("1 stage")
// show this notification five seconds from now
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
print("2 stage")
//UNUserNotificationCenter.current().delegate = self
// choose a random identifier
let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
print("3 stage")
// add our notification request
UNUserNotificationCenter.current().add(request){ (error : Error?) in
if let theError = error {
print(theError.localizedDescription)
}
}
print("4 stage")
print(UNUserNotificationCenter.current().delegate)
print("ok")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: #escaping () -> Void) {
print("5 stage")
let userInfo = response.notification.request.content.userInfo
let id = "dad"
print("6 stage")
print(response.actionIdentifier)
switch response.actionIdentifier {
case "done":
base.ropes.removeAll(where: {$0.name == id})
break
case UNNotificationDefaultActionIdentifier,
UNNotificationDismissActionIdentifier:
break
default :
break
}
print(base.ropes.count)
completionHandler()
}
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("q")
completionHandler([.badge,.banner,.sound,.list])
}
}
I’m declaring this class at sheet view
struct Adding: View {
private let publisher = Notfication()
And using it when I press the button in a sheet view
Button(action: {
RopesDB.ropes.append(rope(name: answer.answer))
publisher.request(answer: RopesDB.ropes.last!, RopesBas: RopesDB)
dismiss()
}, label: {
HStack{
Spacer()
Text(answer.answer)
Spacer()
}
I’ve tried to put delegate into
class AppDelegate: NSObject, UIApplicationDelegate{
internal func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
let center = UNUserNotificationCenter.current()
let options : UNAuthorizationOptions = [.alert, .badge, .sound]
center.requestAuthorization(options: options) { granted, error in
if granted{
UNUserNotificationCenter.current().delegate = Notfication()
}
if let error = error {
print(error.localizedDescription)
}
}
return true
}
//
}
And into the class where it comment
What my mistake?
IDE Swiftplaygrounds(iPad 9, iOS 15.5)
Apple states in its documentation that notifications are only shown when the app is in the background. When the app already is in the foreground, the notification will be directly passed into your app:
https://developer.apple.com/documentation/usernotifications/handling_notifications_and_notification-related_actions
You will need to receive the notification in your delegate's userNotificationCenter(_:willPresent:withCompletionHandler:) method and there your app can decide what to actually do with it. E.g. throw the user to a certain view, show a modal etc.
I found out that this thing can’t work on Playgrounds, I suppose

Why aren't local notifications showing up on Mac?

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.

Can you disable App-opening mechanism when the user presses the Notification Banner?

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()
}
}

Why is the local notification I created with UNUserNotificationCenter not shown in the upper-right corner of my screen?

Running the code below doesn't show the notification in the upper-right corner of my screen (as a banner or alert). The notification is shown in the notification center.
I made sure "Do not disturb" is disabled on my system. I also tried both the "Banner" and "Alert" setting in System Preferences -> Notifications -> Name of my app.
Source:
import Cocoa
import UserNotifications
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
let notificationCenter = UNUserNotificationCenter.current()
notificationCenter.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in
print("requestNotificationAuthorization: granted=\(granted) error=\(String(describing: error))")
}
let content = UNMutableNotificationContent()
content.title = "bar"
content.body = "foo"
content.categoryIdentifier = "alarm"
let uuidString = UUID().uuidString
let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 2, repeats: false)
let request = UNNotificationRequest(identifier: uuidString, content: content, trigger: trigger)
notificationCenter.add(request, withCompletionHandler: { error in
print("completion handler called")
if error != nil {
print("notification center error: \(String(describing: error))")
}
})
}
func applicationWillTerminate(_ aNotification: Notification) {
}
}
Console output:
requestNotificationAuthorization: granted=true error=nil
completion handler called
if you want to see notification banner while app is in foreground use below method
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification,
withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
// Forground notifications.
completionHandler([.alert, .sound])
}
Wanna see a magic trick?
If you are working with multiple displays, unplug them, and tadaa - notifications work.
I made sure "Do not disturb" is disabled on my system.
Go to Mac System Preferences->Notifications->Do not disturb (1st item on the list)
Turns out, by default, if you are mirroring your display, the "Do not disturb" mode gets enabled and you don't get any notifications. So, uncheck it, plug your other display back in and keep coding.
This is so stupid that it's almost funny.
The notification isn't shown when the app is running in the foreground. Relevant documentation.

Add Local Notification in iOS 10 - Swift 3

So I been trying to add a notification to the new UNUserNotificationCenter, but I don't seem to get it.
My view controller has an action:
#IBAction func sendPressed(_ sender: AnyObject) {
let content = UNMutableNotificationContent()
content.title = "Hello"
content.body = "What up?"
content.sound = UNNotificationSound.default()
// Deliver the notification in five seconds.
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5, repeats: false)
let request = UNNotificationRequest.init(identifier: "FiveSecond", content: content, trigger: trigger)
// Schedule the notification.
let center = UNUserNotificationCenter.current()
center.add(request) { (error) in
print(error)
}
print("should have been added")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let center = UNUserNotificationCenter.current()
center.requestAuthorization([.alert, .sound]) { (granted, error) in
}
}
And I have a Notification Content Extension in the project as well, but it does not seem to be triggered at all, any ideas what I'm missing? I'm trying the example from the user documentation, but it's not telling me much more or I have missed it.
Here: https://developer.apple.com/reference/usernotifications/unmutablenotificationcontent
Also:
https://developer.apple.com/reference/usernotificationsui
https://developer.apple.com/reference/usernotifications
Edit:
So putting the app in the background did the trick.
You need to register for Notification...I tried and this works.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let center = UNUserNotificationCenter.current()
center.requestAuthorization([.alert, .sound]) { (granted, error) in
// Enable or disable features based on authorization.
}
return true
}
Edit: You dont need to put your app in background to present notification from iOS 10 onwards.
Use below callback to configure notification to present in foreground.
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void)
Here is a sample project.
With Objective-C implemation:
I have wrote a Demo project here: iOS10AdaptationTips .
import UserNotifications
///Notification become independent from Foundation
#import UserNotifications;
request authorization for localNotification
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert)
completionHandler:^(BOOL granted, NSError * _Nullable error) {
if (!error) {
NSLog(#"request authorization succeeded!");
[self showAlert];
}
}];
Request Authorization:
schedule localNotification
update application icon badge number
// //Deliver the notification at 08:30 everyday
// NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
// dateComponents.hour = 8;
// dateComponents.minute = 30;
// UNCalendarNotificationTrigger *trigger = [UNCalendarNotificationTrigger triggerWithDateMatchingComponents:dateComponents repeats:YES];
UNMutableNotificationContent *content = [[UNMutableNotificationContent alloc] init];
content.title = [NSString localizedUserNotificationStringForKey:#"Elon said:" arguments:nil];
content.body = [NSString localizedUserNotificationStringForKey:#"Hello Tom!Get up, let's play with Jerry!"
arguments:nil];
content.sound = [UNNotificationSound defaultSound];
/// 4. update application icon badge number
content.badge = #([[UIApplication sharedApplication] applicationIconBadgeNumber] + 1);
// Deliver the notification in five seconds.
UNTimeIntervalNotificationTrigger *trigger = [UNTimeIntervalNotificationTrigger
triggerWithTimeInterval:5.f repeats:NO];
UNNotificationRequest *request = [UNNotificationRequest requestWithIdentifier:#"FiveSecond"
content:content trigger:trigger];
/// 3. schedule localNotification
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {
if (!error) {
NSLog(#"add NotificationRequest succeeded!");
}
}];
then it will appear like this:
In Background :
Lock Screen:
If Repeat by default only show one
instead of show many on the lock screen on iOS9:
and also support 3D Touch automatically
I write a Demo here: iOS10AdaptationTips .
I solved my problem as follows (Firebase, Swift 3):
Find this method on your AppDelegate:
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
Find this line:
completionHandler()
End set:
completionHandler([.alert,.sound,.badge])
notifications are not firing if you not pass your presentation options to completionHandler method.
Here are a few steps:
Make sure you have the permission. If not, use UNUserNotificationCenter.current().requestAuthorization to get that. Or follow the answer if you want to show the request pop up more than once.
If you want to show the notification foreground, having to assign UNUserNotificationCenterDelegate to somewhere.
Show me the code
#IBAction func sendPressed(_ sender: AnyObject) {
let content = UNMutableNotificationContent()
content.title = "Hello"
content.body = "What up?"
content.sound = UNNotificationSound.default()
let trigger = UNTimeIntervalNotificationTrigger.init(timeInterval: 5, repeats: false)
let request = UNNotificationRequest.init(identifier: "FiveSecond", content: content, trigger: trigger)
let center = UNUserNotificationCenter.current()
center.add(request) { (error) in
print(error)
}
}
override func viewDidLoad(_ animated: Bool) {
super.viewDidLoad(animated)
// Assign the delegate
UNUserNotificationCenter.current().delegate = self
// Ask the permission
let center = UNUserNotificationCenter.current()
center.requestAuthorization([.alert, .sound]) { (granted, error) in
if granted {
// do something
}
}
}
// Remember to add UNUserNotificationCenterDelegate to your view controller
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: #escaping (UNNotificationPresentationOptions) -> Void) {
print("Got the msg...")
completionHandler([.badge, .sound, .alert])
}
I have made an implementation for Swift 3 which may help, you can check it here: https://stackoverflow.com/a/45381380/2296630