Ios 应用程序关闭时的iBeacon通知

Ios 应用程序关闭时的iBeacon通知,ios,swift,ibeacon,Ios,Swift,Ibeacon,我正在尝试在应用程序关闭时输入一个区域(在最近距离)时向用户发送本地通知。如果应用程序在后台,我当前可以使用它,但如果应用程序关闭,则无法使用它。我读过其他帖子说这是可能的,但没有一个解决方案有效,而且已经过时了。如果您能在Swift 3中提供帮助,我将不胜感激 以下是我的代码(全部在AppDelegate中): 在didFinishLaunchingWithOptions中: locationManager.delegate = self locationManager.pausesLocat

我正在尝试在应用程序关闭时输入一个区域(在最近距离)时向用户发送本地通知。如果应用程序在后台,我当前可以使用它,但如果应用程序关闭,则无法使用它。我读过其他帖子说这是可能的,但没有一个解决方案有效,而且已经过时了。如果您能在Swift 3中提供帮助,我将不胜感激

以下是我的代码(全部在AppDelegate中):

在didFinishLaunchingWithOptions中:

locationManager.delegate = self
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.allowsBackgroundLocationUpdates = true             
locationManager.requestAlwaysAuthorization()

let uuid = UUID(uuidString: "someuuid")!
let beaconRegion = CLBeaconRegion(proximityUUID: uuid, identifier: "SomeBeacon")
beaconRegion.notifyEntryStateOnDisplay = true
beaconRegion.notifyOnEntry = true
beaconRegion.notifyOnExit = true
locationManager.startMonitoring(for: beaconRegion)
locationManager.startRangingBeacons(in: beaconRegion)

我还实现了didRangeBeacons。

代码看起来正确,允许在应用程序关闭时进行检测。您不需要:

locationManager.pausesLocationUpdatesAutomatically = false
locationManager.allowsBackgroundLocationUpdates = true   
但他们不应该伤害任何东西

你只提到了应用程序关闭时的问题,所以我认为前景检测工作正常。是吗?如果没有,请先对此进行故障排除

通常很难正确测试应用程序关闭的用例,因为测试设置问题导致失败。以下几点提示可能会有所帮助:

  • iOS只会在认为区域外时发送区域进入事件。通常在测试中,它认为它位于某个区域,所以您不会得到一个事件。要确保您不在区域内,请关闭信标或在应用程序位于前景时超出范围,然后等待收到退出回调。只有这样,你才能关闭应用程序来测试关闭检测

  • 如果重新启动手机,请始终在启动后等待5分钟,以确保CoreLocation已完全初始化。确保你遵守了规则1

  • 确保手机上没有安装大量其他信标应用程序占用所有蓝牙检测硬件加速插槽。如果您这样做,后台检测可能会延迟15分钟。卸载所有beacon应用程序,然后卸载并重新安装您的应用程序


  • 如果您按照上面的测试提示操作,您应该会在信标位于附近的几秒钟内看到检测回调。

    更新,正如@davidgyoung在另一个问题上向我指出的那样,这种使用
    UNLocationNotificationTrigger
    的方法不会向您报告主标识符和次标识符,因为它使用的是监控API,而不是获取主标识符和次标识符所需的范围。这限制了您可以使用此包装器API执行的所有操作。它确实很方便,但没有人们希望的那么有用


    据我所知,新的(iOS 10,Swift 3)方法是使用
    UserNotifications
    库,并通过
    UNNotificationRequest
    实现它。您可以通过
    UNLocationNotificationTrigger
    将信标区域传递给它。现在我知道,对于您想要的内容(应用程序关闭时通知),这似乎是违反直觉的,但是,您希望将
    nslocationwhenUsageDescription
    键添加到您的
    Info.plist
    中,而不是
    NSLocationAlwaysUsageDescription
    。我不知道为什么会这样,但这是必要的一步。以下是我用于创建(iBeacon)基于位置的通知的代码:

    // Ensure you use a class variable in order to ensure the location 
    // manager is retained, otherwise the alert message asking you to
    // authorize it will disappear before you can tap "allow" which
    // will keep it from working
    let locationManager = CLLocationManager()
    
    // ...
    
    // Somewhere in your class (e.g. AppDelegate or a ViewController)
    self.locationManager.requestWhenInUseAuthorization()
    
    let region = CLBeaconRegion(proximityUUID: UUID(uuidString: "YOUR-UNIQUE-UUID-STRING")!, identifier: "com.yourcompany.youridentifier")
    region.notifyOnEntry = true
    region.notifyOnExit = false
    
    let content = UNMutableNotificationContent()
    content.title = "Notification Title"
    content.body = "Body text goes here"
    
    // Not sure if repeats needs to be set to true here, but that's
    // how I've implemented it
    let trigger = UNLocationNotificationTrigger(region: region, repeats: true)
    
    // Use the same identifier each time to ensure it gets overwritten
    // in the notification system
    let identifier = "BeaconLocationIdentifier"
    let request = UNNotificationRequest.init(identifier: identifier, content: content, trigger: trigger)
    
    // This is probably unnecessary since we're using the same identifier
    // each time this code is called
    UNUserNotificationCenter.current().removeAllPendingNotificationRequests()
    
    // Make sure you set the notification center's delegate. My 
    // containing class is the AppDelegate. I implement the delegate
    // methods there.
    UNUserNotificationCenter.current().delegate = self
    UNUserNotificationCenter.current().add(request, withCompletionHandler: { (error) in
    
    })
    
    // Not sure if this is required either, but after I added this, everything
    // started working
    self.locationManager.startRangingBeacons(in: region)
    
    确保您实现了notification center委派方法:

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        // Called when the notification has been swiped or tapped by the user
    
        // Do something with the response here
    
        // Make sure you call the completion handler
        completionHandler()
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        // Called when the app is in the foreground
    
        // Do something with the notification here
    
        // Make sure you call the completion handler
        completionHandler([.alert, .sound])
    }
    
    最后,您需要首先授权通知,以使这一切正常工作。您可以使用此代码执行以下操作:

    let options: UNAuthorizationOptions = [.alert,.sound]
    UNUserNotificationCenter.current().requestAuthorization(options: options) {
        (granted, error) in
        if !granted {
            debugPrint("Something went wrong")
        } else {
            debugPrint("Notifications granted")
    
        }
    }
    

    最后一点提示:我有一个旧金属罐,它(某种程度上)充当我正在使用的信标的法拉第笼。我只是在那里关闭了一分钟左右的信号灯,然后应用程序检测到我已经超出了范围。这比试着走得离灯塔足够远或取下电池(这对我来说根本不起作用)更方便。有些信标的信号比其他信标强,可能仍能通过tin,所以YMMV。

    你能显示你的代码吗?如果它在后台工作,则不清楚为什么它在关闭应用程序时不工作。刚刚更新,将感谢您的帮助。