应用关闭时的 iBeacon 通知

Posted

技术标签:

【中文标题】应用关闭时的 iBeacon 通知【英文标题】:iBeacon Notification When App Closed 【发布时间】:2017-01-27 11:11:13 【问题描述】:

我正在尝试在应用程序关闭时在输入区域(距离很近)时向用户发送本地通知。如果应用程序在后台,我目前可以正常工作,但如果应用程序关闭,则无法正常工作。我读过其他帖子说这是可能的,但是这些解决方案都不起作用,而且它们已经过时了。我会感谢 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。

【问题讨论】:

你能显示你的代码吗?如果它在后台运行,则不清楚为什么它在应用关闭时无法运行。 刚刚更新,感谢您的帮助。 【参考方案1】:

代码看起来正确,可以在应用关闭时进行检测。你不需要:

locationManager.pausesLocationUpdatesAutomatically = false
locationManager.allowsBackgroundLocationUpdates = true   

但他们不应该伤害任何东西。

您只提到关闭应用程序的问题,所以我认为前景检测工作正常。可以?如果没有,请先解决此问题。

由于测试设置问题而导致失败的应用关闭用例通常很难正确测试。一些提示可能会有所帮助:

    ios 仅在认为超出区域时才会发送区域进入事件。通常在测试中它认为它在区域中,所以你没有得到一个事件。为确保您不在该区域内,请关闭您的信标或走出范围将应用程序置于前台,然后等到您收到退出回调。只有这样你才能杀死应用程序来测试封闭检测。

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

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

如果您按照上面的测试提示进行操作,您应该会在信标出现后几秒钟内看到检测回调。

【讨论】:

【参考方案2】:

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


据我所知,新的(iOS 10、Swift 3)方法是使用UserNotifications 库并使用UNNotificationRequest 实现它。您可以通过UNLocationNotificationTrigger 将信标区域传递给它。现在我知道您想要的东西似乎与直觉相反(应用程序关闭时的通知),但是,您想将NSLocationWhenInUseUsageDescription 键添加到您的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)

确保实现通知中心委托方法:

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")

    

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

【讨论】:

以上是关于应用关闭时的 iBeacon 通知的主要内容,如果未能解决你的问题,请参考以下文章

屏幕关闭时的 iBeacon 事件

一个 ibeacon(信标)可以模仿 NFC 的近距离发送通知吗? [关闭]

如何在后台应用程序和iphone重启时使用ibeacon[关闭]

快速,在后台检测 ibeacons 并在范围内发送通知

您可以在退出区域时对 ibeacon 通知应用时间限制吗?

iBeacon-App:从锁屏启动时的自定义代码