swift - 如何每月最多显示一次 iOS 区域通知?

标签 swift notifications region

我的应用程序的部署目标是 10.0,我使用 UNUserNotificationCenter 来显示区域通知,即使在应用程序关闭/终止时也是如此。但新的任务是最多一个月显示一次,尽管用户可能每月进入该区域不止一次。

到目前为止我尝试过的(效果很好)是...

    let content = UNMutableNotificationContent()

    content.title = "... Reminder"
    content.body = "Welcome to \(element.name). Please let us know how we can serve you and your loved ones, and we hope ... will simplify your visit here."
    content.sound = UNNotificationSound.default
    content.categoryIdentifier = "LOCATION_CAT"

    let centerCoordinate2D = element.location.coordinate
    let identifierName = element.name.replacingOccurrences(of: " ", with: "_")
    let region = CLCircularRegion(center: centerCoordinate2D, radius: 300, identifier: identifierName)
    region.notifyOnExit = false
    region.notifyOnEntry = true
    let trigger = UNLocationNotificationTrigger(region: region, repeats: true)

    // request = content + trigger
    let request = UNNotificationRequest(identifier: "REGION \(element.name)", content: content, trigger: trigger)

    // add (or "schedule") request to center
    let center = UNUserNotificationCenter.current()
    center.add(request, withCompletionHandler: { (error: Error?) in

        if let theError = error {
            print(theError.localizedDescription)
        }
    })

但是,为了让它每月最多发生一次,我做了以下事情:

    let centerCoordinate2D = element.location.coordinate
    let identifierName = element.name.replacingOccurrences(of: " ", with: "_")
    let region = CLCircularRegion(center: centerCoordinate2D, radius: 300, identifier: identifierName)
    region.notifyOnExit = true
    region.notifyOnEntry = true

    R.shared.appleLocationManager.startMonitoring(for: region)

同样在 AppDelegate.swift 中,

extension AppDelegate: CLLocationManagerDelegate {

    // called when user Enters a monitored region
    func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {

        print("AppDelegate.locationManager( didEnterRegion ): called with region identifier: \(region.identifier)")

        if region is CLCircularRegion {
            // Do what you want if this information
            self.handleEvent(forRegion: region)
        }
    }

    func handleEvent(forRegion region: CLRegion) {

        // we save 'date' with "NOTIFICATION DATE request_identifier" as its key.
        let key = "NOTIFICATION DATE \(region.identifier)"
        let defaultValue = defaults.double(forKey: key)
        if defaultValue == 0 {
            print("AppDelegate.handleEvent(): need to show notification: no key")

            // set value first.
            defaults.set(Date().timeIntervalSince1970, forKey: key)

            showNotification(forRegion: region)

        } else {
            let diff = Date().timeIntervalSince(Date(timeIntervalSince1970: defaultValue))
            if  diff > 60 * 60 * 24 * 30 {
                print("AppDelegate.handleEvent(): need to show notification: diff > 30 days")

                // set value first.
                defaults.set(Date().timeIntervalSince1970, forKey: key)

                showNotification(forRegion: region)

            } else {
                // just pass.
                print("AppDelegate.handleEvent(): need NOT to show notification: diff: \(dot2(diff / 24 / 60)) mins")
            }
        }
    }

    func showNotification(forRegion region: CLRegion, message: String = "") {

        // customize your notification content
        let content = UNMutableNotificationContent()
        content.title = "... Reminder"
        let hospitalName = region.identifier.replacingOccurrences(of: "_", with: " ")
        content.body = "Welcome to \(hospitalName). \(message) Please let us know how we can serve you and your loved ones, and we hope ... will simplify your visit here."
        content.sound = UNNotificationSound.default

        // the actual trigger object
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0,
                                                        repeats: false)

        // notification unique identifier, for this example, same as the region to avoid duplicate notifications
        let identifier = "REGION \(hospitalName)"

        // the notification request object
        let request = UNNotificationRequest(identifier: identifier,
                                            content: content,
                                            trigger: trigger)

        // trying to add the notification request to notification center
        UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in

            if let theError = error {
                print(theError.localizedDescription)
            }
        })
    }

以下,仍然是 AppDelegate 类:

let appleLocationManager = CLLocationManager()

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    self.appleLocationManager.delegate = self
    ...
}

我认为代码中存在错误,但我不清楚即使在应用程序关闭/终止时是否调用 locationManager( didExitRegion: ) - 在这种情况下 appleLocationManager不是活着?

如果我不能使用 locationManager( didExitRegion: ) 来解决这个问题,我该怎么做才能使区域通知最多每月发生一次?我也知道有一种不同类型的触发器,UNTimeIntervalNotificationTrigger 或 UNLocationNotificationTrigger,我想以某种方式使用它们来解决这个问题,但是有没有办法让它运行我的一些代码,即使应用程序没有运行全部?如果这都解决不了,那不就说区域通知限制太多了吗?

最佳答案

如 Apple 文档所述,使用 CLLocationManager 进行区域监控会在需要时唤醒您的应用。

比较https://developer.apple.com/documentation/corelocation/monitoring_the_user_s_proximity_to_geographic_regions

Whenever the user crosses the boundary of one of your app's registered regions, the system notifies your app. If an iOS app is not running when the boundary crossing occurs, the system tries to launch it. An iOS app that supports region monitoring must enable the Location updates background mode so that it can be launched in the background.

您还可以使用 UIApplication.LaunchOptionsKey 检测应用是否通过区域通知启动。

Boundary crossing notifications are delivered to your location manager's delegate object. Specifically, the location manager calls the locationManager(:didEnterRegion:) or locationManager(:didExitRegion:) methods of its delegate. If your app was launched, you must configure a CLLocationManager object and delegate object right away so that you can receive these notifications. To determine whether your app was launched for a location event, look for the UIApplication.LaunchOptionsKey in the launch options dictionary.

关于swift - 如何每月最多显示一次 iOS 区域通知?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54431363/

相关文章:

JavaScript:避免重复的通知

iphone - 如何比较两个不同的 map View 区域并找出它们之间的差异

swift - 如何在 OS X 中对鼠标按下的标签控件进行操作

android - 默认通知背景颜色

Android - 收到通知但没有弹出通知(前景)

c - 在C语言中,如何找到划分为不同扇区的六边形形状中的点的位置

.net - 州/地区/省命名约定

ios - removeFromSuperview() 不工作

iOS - 模棱两可的布局

swift - Swift 代码有没有办法检测它是否在 Playground 上运行?