我正在尝试在应用关闭时输入区域(在近距离)向用户发送本地通知。如果应用程序在后台,我现在可以使用它,但如果应用程序关闭,则无法使其正常工作。我已经阅读了其他帖子,说这是可能的,但没有一个解决方案有效,而且它们已经过时了。我很欣赏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)
我也实现了.RangeBeacons。
答案 0 :(得分:3)
代码看起来正确,以便在应用关闭时进行检测。你不需要:
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.allowsBackgroundLocationUpdates = true
但他们不应该伤害任何东西。
你只提到关闭app的麻烦,所以我认为前景检测工作正常。可以?如果没有,请先解决此问题。
通常很难正确测试应用程序关闭的用例,导致由于测试设置问题导致的失败。一些提示可能有所帮助:
iOS只会在认为超出区域时发送区域输入事件。通常在测试中它认为它在区域中,所以你不会得到一个事件。为了确保您不在地区,请关闭您的信标或使用前景中的应用超出范围,并等到您获得退出回拨。只有这样才能杀死应用程序以测试封闭检测。
如果重新启动手机,请始终在启动后等待5分钟,以确保CoreLocation已完全初始化。并确保您遵守了规则1.
确保手机上没有安装大量其他信标应用,占用所有蓝牙检测硬件加速插槽。如果这样做,背景中的检测可延迟最多15分钟。卸载所有beacon应用程序,然后卸载并重新安装。
如果您按照上面的测试提示,您应该会在信标附近的几秒钟内看到检测回调。
答案 1 :(得分:0)
更新正如@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。