UNNotification 的重复间隔

Posted

技术标签:

【中文标题】UNNotification 的重复间隔【英文标题】:Repeat interval for UNNotification 【发布时间】:2019-01-07 14:15:56 【问题描述】:

有一个选项可以设置 UILocalNotification 的重复间隔。由于 Apple 已弃用 UILocalNotification 并建议改用 UNNotification,因此我找不到使用 UNNotification 设置具有自定义重复间隔的通知的方法。

    var comp = DateComponents()
    comp.year = 2019
    comp.month = 1
    comp.day = 9
    comp.hour = 14
    comp.minute = 14
    comp.second = 0
    let calendar = Calendar.current
    let notification: UILocalNotification = UILocalNotification()
    notification.category = "Daily Quote"
    notification.alertBody = "Body"
    notification.alertTitle = "Title"
    notification.fireDate = calendar.date(from: comp)
    notification.repeatInterval = NSCalendar.Unit.day
    UIApplication.shared.scheduleLocalNotification(notification)

那么我可以使用新的 UNNotification 设置一个类似的通知,在等待初始通知后每小时或每天重复一次吗?

【问题讨论】:

这已经有很多答案了,尤其是在警报的情况下。输入问题时查看相关链接,并使用此处描述的方法和相关:***.com/questions/38380783/… @Nithin,你试过我下面的例子吗? @mijokaliger 实际上情况就像我需要将通知安排在下周二并每天重复一次。我认为您的解决方案无法做到这一点。 @NithinDevN 我已经编辑了我的答案 【参考方案1】:

要模仿 UILocalNotification 的 API fireDaterepeatInterval,您可以创建两个触发器,一个用于 fireDate 的非重复触发器,另一个用于 repeatInterval 的重复触发器。

这是一个例子:

import UserNotifications

/// Schedules notificaiton to fire at specific date, and then it repeats by specified repeat component
/// (week, day, hour, etc.) and repeat interval. For example to repeat every 20minutes repeatComponent
/// would be .minute and repeatInterval would be 20.
/// - Parameters:
///   - fireDate: Date for initial notification delivery
///   - repeatComponent: Component by which repeating would be performed (week, day, hour, etc.)
///   - repeatInterval: Interval by which repeating by specified component would be performed. Defaults value is 1.
func scheduleNotification(fireDate: Date, repeatComponent: Calendar.Component, repeatInterval: Int = 1) 

    let content = UNMutableNotificationContent()
    content.title = "Daily Quote"
    content.body = "Inspirational quote."
    content.categoryIdentifier = "quote.category"

    UNUserNotificationCenter.current().requestAuthorization(
        options: [.alert,.sound])
    
        (granted, error) in

        if let error = error 
            print("granted, but Error in notification permission:\(error.localizedDescription)")
        

        let fireTrigger = UNTimeIntervalNotificationTrigger(timeInterval: fireDate.timeIntervalSinceNow, repeats: false)

        let fireDateRequest = UNNotificationRequest(identifier: "quote.starter", content: content, trigger: fireTrigger)

        UNUserNotificationCenter.current().add(fireDateRequest) (error) in
            if let error = error 
                print("Error adding firing notification: \(error.localizedDescription)")
             else 

                if let firstRepeatingDate = Calendar.current.date(byAdding: repeatComponent, value: repeatInterval, to: fireDate) 

                    let repeatingTrigger = UNTimeIntervalNotificationTrigger(timeInterval: firstRepeatingDate.timeIntervalSinceNow, repeats: true)

                    let repeatingRequest = UNNotificationRequest(identifier: "quote.repeater", content: content, trigger: repeatingTrigger)

                    UNUserNotificationCenter.current().add(repeatingRequest)  (error) in
                        if let error = error 
                            print("Error adding repeating notification: \(error.localizedDescription)")
                         else 
                            print("Successfully scheduled")
                            // Successfully scheduled
                        
                    

                
            
        

        UNUserNotificationCenter.current().delegate = self
    

委托(用于调试):

extension ViewController: UNUserNotificationCenterDelegate 
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) 
        print("\(notification.request.identifier): \(Date())")
        UNUserNotificationCenter.current().getPendingNotificationRequests  (requests) in
            for request in requests 
                if let timeIntervalTrigger = request.trigger as? UNTimeIntervalNotificationTrigger 
                    print(Date(timeIntervalSinceNow: timeIntervalTrigger.timeInterval))
                

            
        
    

根据您的要求使用:

let interval = 7 // One week from now
if let fireDate = Calendar.current.date(byAdding: .day, value: interval, to: Date()) 
    _ = scheduleNotification(fireDate: fireDate, repeatComponent: .day)


注意

指定重复间隔小于 60 秒会导致异常:

'NSInternalInconsistencyException',原因:'如果重复,时间间隔必须至少为 60'

【讨论】:

什么是类别标识符?如果我每天有 2 个本地通知,我应该设置不同的标识符吗? 当我使用 timeIntervalSince1970 而不是 timeIntervalSinceNow 时会发生什么? @mijokaliger 嗯。我认为这里的代码细节没有按预期工作。我认为打算在延迟后调用 UNUserNotificationCenter.current().add 完成处理程序。然后用它来安排延迟后的重复请求。但是,会立即调用 UNUserNotificationCenter.current().add 完成处理程序。延迟后调用的是委托方法。因此,AFAIK,必须使用委托方法来安排重复请求。 如果您正在寻找它在后台运行,这将是不可靠的。除非用户与通知交互,否则不会调用委托方法。请参阅developer.apple.com/documentation/usernotifications/…中的文档 代码中repeatingTrigger的timeInterval是根据当前时间计算的,但我认为repeatingTrigger与当前时间无关。该行可以这样更改: let repeatingTrigger = UNTimeIntervalNotificationTrigger(timeInterval: firstRepeatingDate.timeIntervalSince(fireDate), repeats: true)【参考方案2】:

你应该使用UNTimeIntervalNotificationTrigger 查看文档https://developer.apple.com/documentation/usernotifications/untimeintervalnotificationtrigger

【讨论】:

以上是关于UNNotification 的重复间隔的主要内容,如果未能解决你的问题,请参考以下文章

重复间隔设置为每小时时 UILocalNotification 应用程序崩溃

iOS10 推送必看 UNNotificationContentExtension

切换到 UNNotification 时,不再显示通知

UNNotification 本地通知和请勿打扰

是否可以在一定时间后使 UNNotification 过期或消失?

在特定时间触发后如何重复本地通知