Iphone:Daily Local Notifications

Daily Local Notifications Are Not Working

Look at the comments within the code

import SwiftUI
//struct and class should start with an uppercase
struct NotificationView: View {
//Central location for Notification code including the delegate
// A call to the notificationManager just like the line of code below has to be included in
// application(_:willFinishLaunchingWithOptions:) or
// application(_:didFinishLaunchingWithOptions:)
//https://developer.apple.com/documentation/usernotifications/unusernotificationcenterdelegate
//https://www.hackingwithswift.com/quick-start/swiftui/how-to-add-an-appdelegate-to-a-swiftui-app
let notificationManager: NotificationManager = NotificationManager.shared
var body: some View {
VStack {
VStack {
Button("Request Permission") {
//Call a func here don't define it
notificationManager.requestAuthorization()
}
.frame(width: 200, height: 60, alignment: .center)
.foregroundColor(.black)
.background(Color.blue)
.cornerRadius(10.0)
.padding()
Button("Add Notifications For Morning") {
//Unique date components
var dateComponents = DateComponents()
dateComponents.hour = 6
dateComponents.minute = 30
//Reusable method
self.notificationManager.scheduleTriggerNotification(title: "Morning Time", body: "Wake Up And Be Productive!", categoryIdentifier: "reminder", dateComponents: dateComponents, repeats: true)
}
.padding()
Button("Add Notifications For Middle Of The Day") {
var dateComponents = DateComponents()
dateComponents.hour = 12
dateComponents.minute = 30
//Reusable method
self.notificationManager.scheduleTriggerNotification(title: "Middle Of The Day", body: "Did you have your daily run?", categoryIdentifier: "reminder", dateComponents: dateComponents, repeats: true)

}
.padding()
Button("Add Notifications For Night") {
var dateComponents = DateComponents()
dateComponents.hour = 20
dateComponents.minute = 51
//Reusable method
self.notificationManager.scheduleTriggerNotification(title: "Night Time", body: "Time to sleep", categoryIdentifier: "reminder", dateComponents: dateComponents, repeats: true)

}
.foregroundColor(.blue)
.padding()

Button("Print Notifications") {
//Reusable method
self.notificationManager.printNotifications()
}
.foregroundColor(.blue)
.padding()
Button("Delete Notifications") {
//Reusable method
self.notificationManager.deleteNotifications()
}
.foregroundColor(.blue)
.padding()
}
}
}
}
//You need a central location for the notification code because
// it is needed in more than 1 spot. At launch in the AppDelegate
// and wherever you schedule your notifications
class NotificationManager: NSObject, UNUserNotificationCenterDelegate{
//Singleton is requierd because of delegate
static let shared: NotificationManager = NotificationManager()
let notificationCenter = UNUserNotificationCenter.current()

private override init(){
super.init()
//This assigns the delegate
notificationCenter.delegate = self
}

func requestAuthorization() {
print(#function)
notificationCenter.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
if granted {
print("Access Granted!")
} else {
print("Access Not Granted")
}
}
}

func deleteNotifications(){
print(#function)
notificationCenter.removeAllPendingNotificationRequests()
}
///This is just a reusable form of all the copy and paste you did in your buttons. If you have to copy and paste make it reusable.
func scheduleTriggerNotification(title: String, body: String, categoryIdentifier: String, dateComponents : DateComponents, repeats: Bool) {
print(#function)
let content = UNMutableNotificationContent()
content.title = title
content.body = body
content.categoryIdentifier = categoryIdentifier
content.sound = UNNotificationSound.default

let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: repeats)

let request = UNNotificationRequest(identifier: UUID().uuidString, content: content, trigger: trigger)
notificationCenter.add(request)
}
///Prints to console schduled notifications
func printNotifications(){
print(#function)
notificationCenter.getPendingNotificationRequests { request in
for req in request{
if req.trigger is UNCalendarNotificationTrigger{
print((req.trigger as! UNCalendarNotificationTrigger).nextTriggerDate()?.description ?? "invalid next trigger date")
}
}
}
}
//MARK: UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

completionHandler(.banner)
}
}
struct NotificationView_Previews: PreviewProvider {
static var previews: some View {
NotificationView()
}
}

How to send a localNotification at a specific time everyday, even if that time has passed?

Updated @Paulw11 's answer to Swift 3.0 and wrapped up in a function:

/// Set up the local notification for everyday
/// - parameter hour: The hour in 24 of the day to trigger the notification
class func setUpLocalNotification(hour: Int, minute: Int) {

// have to use NSCalendar for the components
let calendar = NSCalendar(identifier: .gregorian)!;

var dateFire = Date()

// if today's date is passed, use tomorrow
var fireComponents = calendar.components( [NSCalendar.Unit.day, NSCalendar.Unit.month, NSCalendar.Unit.year, NSCalendar.Unit.hour, NSCalendar.Unit.minute], from:dateFire)

if (fireComponents.hour! > hour
|| (fireComponents.hour == hour && fireComponents.minute! >= minute) ) {

dateFire = dateFire.addingTimeInterval(86400) // Use tomorrow's date
fireComponents = calendar.components( [NSCalendar.Unit.day, NSCalendar.Unit.month, NSCalendar.Unit.year, NSCalendar.Unit.hour, NSCalendar.Unit.minute], from:dateFire);
}

// set up the time
fireComponents.hour = hour
fireComponents.minute = minute

// schedule local notification
dateFire = calendar.date(from: fireComponents)!

let localNotification = UILocalNotification()
localNotification.fireDate = dateFire
localNotification.alertBody = "Record Today Numerily. Be completely honest: how is your day so far?"
localNotification.repeatInterval = NSCalendar.Unit.day
localNotification.soundName = UILocalNotificationDefaultSoundName;

UIApplication.shared.scheduleLocalNotification(localNotification);

}

UNNotificationRequest to send local notification daily at a specific time

You can use UNCalendarNotificationTrigger for creating a notification that fires repeatedly using UNUserNotificationCenter. You can do something like this. The trick is to only have the time component in the Trigger date.

        let center = UNUserNotificationCenter.current()

let content = UNMutableNotificationContent()
content.title = "Attention!"
content.body = "Your daily alert is ready for you!"
content.sound = UNNotificationSound.default

let identifier = "com.yourdomain.notificationIdentifier"

var triggerDate = DateComponents()
triggerDate.hour = 18
triggerDate.minute = 30
let trigger = UNCalendarNotificationTrigger(dateMatching: triggerDate, repeats: true)

let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)

center.add(request, withCompletionHandler: { (error) in
if let error = error {
// Something went wrong
print("Error : \(error.localizedDescription)")
} else {
// Something went right
print("Success")
}
})

How to set up daily local notification for tasks but don't show it when user completes the task before

I ended up using multiple notifications for each weekday but set it up in little different way:

First set up daily reminder using weekday Int as identifier

func setWeekdayReminder(weekday: Int) {
let center = UNUserNotificationCenter.current()
let content = UNMutableNotificationContent()
content.title = "Daily reminder"
content.body = "You still have some tasks to complete today."
content.sound = UNNotificationSound.default
var dateComponents = DateComponents()
dateComponents.hour = 18
dateComponents.minute = 35
dateComponents.weekday = weekday
let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true
let request = UNNotificationRequest(identifier: String(weekday), content: content, trigger: trigger)

center.add(request) { (error) in
if let error = error {
print("Notification Error: ", error)
}
}
}

then i made a function to check if there is any missing day after users launches app (except today, so i won't request todays notification again even after removing it earlier when user completes the task)

func checkDailyReminder() {

let currentWeekday = Calendar.current.component(.weekday, from: Date())

center.getPendingNotificationRequests { (requests) in
var weekdayArray : [Int] = []

for each in requests {
weekdayArray.append(Int(each.identifier)!)
}
for number in 1...7 {
if weekdayArray.contains(number) {
print("weekdayArray contains weekday \(number)")
} else {
print("weekdayArray doesnt contain weekday \(number)")
if number != currentWeekday {
self.setWeekdayReminder(weekday: number)
}
}
}

}
}

Of course it's kind of a hack and when user completes the task and somehow won't go back for a week and open it again on the same weekday then he won't get notification that day but it works for rest of the time.

How Can I Repeat Local Notifications for Evey Hours in Every Day?


let interval:TimeInterval = 60.0 // 1 minute = 60 seconds

let trigger = UNTimeIntervalNotificationTrigger(timeInterval: interval, repeats: true)

Use UNTimeIntervalNotificationTrigger instead of UNCalendarNotificationTrigger because UNCalendarNotificationTrigger object is used when you want to schedule the delivery of a local notification at the specified date and time and UNTimeIntervalNotificationTrigger object is used when you want to schedule the delivery of a local notification after the specified number of seconds elapse.

https://developer.apple.com/documentation/usernotifications/untimeintervalnotificationtrigger

iPhone : Daily local notifications

You just need to properly create a NSDate object to be your fire date (time). Instead of using [NSDate dateByAddingTimeInterval: 20], use something like this:

NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [[NSDateComponents alloc] init];
[components setDay: 3];
[components setMonth: 7];
[components setYear: 2012];
[components setHour: 6];
[components setMinute: 0];
[components setSecond: 0];
[calendar setTimeZone: [NSTimeZone defaultTimeZone]];
NSDate *dateToFire = [calendar dateFromComponents:components];

Here are the Apple NSDateComponents API docs

And then when you add the date to the notification, set the repeat interval to one day:

[localNotification setFireDate: dateToFire];
[localNotification setTimeZone: [NSTimeZone defaultTimeZone]];
[localNotification setRepeatInterval: kCFCalendarUnitDay];

As with all date related code, make sure to test how this works during the switch to daylight savings time, if your time zone uses daylight savings time.



Related Topics



Leave a reply



Submit