简体   繁体   English

如何为任务设置每日本地通知,但在用户之前完成任务时不显示

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

I know similar questions appeared before but I think I need more clarification since i still don't know how to make it done.我知道以前出现过类似的问题,但我认为我需要更多说明,因为我仍然不知道如何完成。 I'm a beginner programmer so please forgive me any mistakes.我是初学者,所以请原谅我的任何错误。

I'm trying to have daily reminders for daily tasks from my app IF user didn't complete it yet, so how can i make it not show up when he had already done the task?如果用户尚未完成,我正在尝试从我的应用程序中获取日常任务的每日提醒,那么当他已经完成任务时,我怎样才能让它不显示呢?

Solutions i found so far suggest to remove pending notification and setting up new one for future date in the same time.到目前为止我发现的解决方案建议删除未决通知并同时为将来的日期设置新的通知。

I successfully set up daily notifications using this code:我使用此代码成功设置了每日通知:

    func sendDailyReminder() {
        let content = UNMutableNotificationContent()
        content.title = "Daily reminder"
        content.body = "You still have task to complete today."
        content.sound = UNNotificationSound.default
        var dateComponents = DateComponents()
        dateComponents.hour = 20
        dateComponents.minute = 00
        let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: true)
        let request = UNNotificationRequest(identifier: "dailyTrigger", content: content, trigger: trigger)

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

i can also successfully remove pending notification with removePendingNotificationRequest method but how can I set it up trigger for tomorrow using dateComponents here?我也可以使用 removePendingNotificationRequest 方法成功删除挂起的通知,但是我如何在这里使用 dateComponents 为明天设置触发器?

Or is there any other way to achieve that?或者还有其他方法可以实现吗? Maybe using background fetch to check if its done just before sending notification?也许在发送通知之前使用后台获取来检查它是否完成?

Some replies i found suggest that its actually impossible but then how any task or to-do app can achieve something like that?我发现一些回复表明这实际上是不可能的,但是任何任务或待办应用程序如何才能实现这样的目标呢?

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首先使用 weekday Int 作为标识符设置每日提醒

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)然后我做了一个 function 来检查用户启动应用程序后是否缺少任何一天(今天除外,所以即使在用户完成任务时提前删除它,我也不会再次请求今天的通知)

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.当然,这是一种黑客行为,当用户完成任务并且以某种方式不会 go 回来一周并在同一个工作日再次打开它时,他那天不会收到通知,但它适用于当时的 rest。

Here is what I came up with.这是我想出的。 Basically everyday the app runs, i'll run this function, to setup local notifications.基本上每天应用程序运行,我都会运行这个 function 来设置本地通知。 It sets them up for the next 14 days.它为接下来的 14 天设置了它们。 Everyday it runs, its always going to be setting up the 14th day from now.它每天运行,它总是会在从现在开始的第 14 天设置。 It will skip the others, they are already pending.它会跳过其他人,他们已经待定。 There is also a function for canceling the notification today, once the task is completed.今天还有一个function取消通知,一旦任务完成。

func setupLocalNotifications() {
    let center = UNUserNotificationCenter.current()
    center.getNotificationSettings { setting in
        guard setting.authorizationStatus == .authorized else {
            print("Not authorized for local push notifications")
            return
        }
        
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyyMMdd"
        dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
        
        let calendar = Calendar.current
        var date = calendar.date(bySettingHour: 14, minute: 0, second: 0, of: Date())!
        center.getPendingNotificationRequests { [weak self] notificationRequests in
            (1...14).forEach { _ in
                //Capture this date.
                let thisDate = date
                
                //Prepare the next date.
                date = calendar.date(byAdding: .day, value: 1, to: date)!
                
                let identifier = dateFormatter.string(from: thisDate)
                
                guard thisDate.isPastDate == false else {
                    Log.d(TAG, "Task Date is in the past - Skipping \(identifier)")
                    return
                }
                
                // Check if we've already scheduled this identifier
                guard notificationRequests.first(where: { $0.identifier == identifier }) == nil else {
                    print("Task Already Scheduled - Skipping \(identifier)")
                    return
                }
                
                // Check if we'e already done our task for the day.
                /*
                 TODO: Special Code Guard that checks if we've already completed the task today. (I took this out because it had project specific code, but you should check your core data or whatever, to see if the task is finished for today.
                 */
                
                let content = UNMutableNotificationContent()
                
                content.title = "Title"
                content.body = "Body"
                
                let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: thisDate)
                
                let trigger = UNCalendarNotificationTrigger(dateMatching: dateComponents, repeats: false)
                
                let request = UNNotificationRequest(identifier: identifier, content: content, trigger: trigger)
                
                let notificationCenter = UNUserNotificationCenter.current()
                notificationCenter.add(request) { (error) in
                    if error != nil {
                        Log.e(TAG, error)
                    }
                    print("Successfully scheduled: \(identifier)")
                }
            }
        }
    }
}

Here is the cancel task function.这是取消任务 function。

func cancelTodaysNotification() {
    let center = UNUserNotificationCenter.current()
    let calendar = Calendar.current
    let dateFrom = calendar.startOfDay(for: Date())
    
    let dateFormatter = DateFormatter()
    dateFormatter.dateFormat = "yyyyMMdd"
    dateFormatter.timeZone = TimeZone(abbreviation: "UTC")
    
    let identifier = dateFormatter.string(from: dateFrom)

    center.removePendingNotificationRequests(withIdentifiers: [identifier])
    
    print("Removed Local Notification for Date: \(identifier)")
    
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 会话完成所有任务后,如何使用AFNetworking 3.0在后台下载大文件并显示本地通知 - How to download large file in background using AFNetworking 3.0 and present local notification when session completes all the tasks 当用户从任务切换器关闭应用程序时显示(本地)通知 - Show (local) notification when user closes app from task switcher 如果应用已经打开,请不要每天发送本地通知 - Don't send daily Local Notification if app already opened 击中区域时不会显示本地通知 - Local notification doesn't show up when hitting region 当用户在iOS中点击本地通知上的“查看”按钮时,如何设置视图? - How would I set up the view when the user taps the View button on a local notification in iOS? 手动设置框架时,UIView子视图不会显示 - UIView Subview don't show up when the frame is set manually 在前台时不显示通知 - Don't show notification when in foreground 使用swift在设定的时间每天重复本地通知 - Repeating local notification daily at a set time with swift 如果将重复设置为每天,则不会触发本地通知 - Local notification not firing if repeat is set to daily 按钮不会在iOS中的本地互动通知上显示 - Buttons don't show on local interactive notification in iOS
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM