CLLocationManager 区域监控:暂停状态检测到达
CLLocationManager Region Monitoring: Detect Arrival in Suspended State
我正在寻找一种方法来跟踪用户是否已到达一组指定的坐标附近。该功能需要在应用程序处于后台时(最好在 100 米内)工作。另外,为了保护电池,理想情况下我不想获得太多坐标读数(也许每 10 分钟一次读数,持续时间不超过几个小时)。
我尝试了几种方法来完成此任务,但无法获得所需的结果:
后台定时器:
我在 (App.delegate)
中添加了后台任务
func applicationDidEnterBackground(_ application: UIApplication)
执行了一个重复的Timer.scheduledTimer来获取坐标并处理
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
检测用户是否在范围内。如果在短期内应用此方法,则此方法有效,但仅在应用程序暂停之前有效,即大约 3 分钟。理想情况下,我不想这么频繁地获取坐标。
区域监控:
我已经初始化了 CLLocationManager,如下所示:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
locationManager.delegate = self
locationManager.allowsBackgroundLocationUpdates = true
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.activityType = .otherNavigation
locationManager.requestAlwaysAuthorization()
}
LocationManager 在应用程序进入后台时启动:
func applicationDidEnterBackground(_ application: UIApplication) {
self.monitorRegionAtLocation(center: CLLocationCoordinate2D(latitude: x, longitude: y), identifier: id)
locationManager.startUpdatingLocation()
}
区域监控代码:
func monitorRegionAtLocation(center: CLLocationCoordinate2D, identifier: String ) {
// Make sure the app is authorized.
if CLLocationManager.authorizationStatus() == .authorizedAlways {
// Make sure region monitoring is supported.
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
// Register the region.
let maxDistance = 200.0
let region = CLCircularRegion(center: center,
radius: maxDistance, identifier: identifier)
region.notifyOnEntry = true
region.notifyOnExit = false
locationManager.startMonitoring(for: region)
}
}
}
并且我为 CLLocationManager 添加了一个 didEnterRegion 功能块:
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if let region = region as? CLCircularRegion {
let identifier = region.identifier
print("FOUND: " + identifier)
}
}
该代码似乎可用于检测进入某个区域,但坐标不会在后台更新。
附加信息
- 我启用了位置更新和后台获取的后台模式
- 我在 Info.plist
中提供了 'Location Always Usage Description' 和 'Location When in Use Usage Description' 的值
- 应用程序设置显示 'Always' 对位置
的权限
我相信一定有更好的方法在后台进行这些类型的检查,但我还没有发现任何在后台检测其他动作的方法。
任何有关此事的指导将不胜感激,如果您需要更多信息,请告诉我,我会尽力提供。
更新:
我已经按照下面评论的建议修改了使用区域监控的方法。
题目说"CLLocationManager Region Monitoring: Detect Arrival in Background"。这是很有可能的,但是在被杀死后检测任何东西是不可能的(来自iOS 7)。
每当用户向上滑动您的应用程序应用程序切换器时,iOS 认为它是因为用户不希望该应用程序 运行 在后台运行,因此所有回调都是停止了。
This answer, this answer and this answer also says the same thing. However Apple doc有点乱。
我个人的观察是,即使在 Killed 模式下,应用程序也会被调用,但很少见。
关于获取位置,只要调用geofencing的delegate方法,就可以轻松获取位置。
而且您的要求确实不需要背景模式。
不幸的是(幸运的是 iOS 用户,因为他们节省了电池电量)我们真的没有办法在应用程序被杀死后的 1 小时内获取位置。
任何位置 update/monitoring 都需要正确配置其位置管理器,以便它能够以最佳状态提供所需的位置更新。在进行后台位置更新时检查一些点很重要:
1.检查位置更新和后台获取的后台模式应该启用
2。检查'Location Always Usage Description'和'Location When in Use Usage Description'中的Info.plist应提供
3。检查您是否想在位置更新之间暂停 - 如果是,那么您需要提供 activity 类型,以便位置管理员可以确定为您暂停位置更新的最佳方式
4。检查您是否要应用距离过滤器 - 您希望用户(设备)移动一些最小量以便位置管理器发送更新的位置
5.检查您是否需要所需的精度-这可能会导致某些精度类型的功耗
在您的代码中,我可以看到位置管理器配置了一些参数,但缺少后台模式的精度和距离过滤器。
locationManager.allowsBackgroundLocationUpdates = true
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.activityType = .otherNavigation
此外,如果您在 Apple doc 中看到暂停位置更新 属性,它表示:
For apps that have in-use authorization, a pause to location updates
ends access to location changes until the app is launched again and
able to restart those updates. If you do not wish location updates to
stop entirely, consider disabling this property and changing location
accuracy to kCLLocationAccuracyThreeKilometers when your app moves to
the background. Doing so allows you to continue receiving location
updates in a power-friendly manner.
本质上它告诉你,如果你想禁用暂停,那么你必须保持精度级别 (kCLLocationAccuracyThreeKilometers)。我猜你的方法中缺少这一点。
此外,您可以检查 this link 实际启动后台任务,然后在后台任务中启动位置管理器监控。
希望对你有帮助。
我正在寻找一种方法来跟踪用户是否已到达一组指定的坐标附近。该功能需要在应用程序处于后台时(最好在 100 米内)工作。另外,为了保护电池,理想情况下我不想获得太多坐标读数(也许每 10 分钟一次读数,持续时间不超过几个小时)。
我尝试了几种方法来完成此任务,但无法获得所需的结果:
后台定时器:
我在 (App.delegate)
中添加了后台任务func applicationDidEnterBackground(_ application: UIApplication)
执行了一个重复的Timer.scheduledTimer来获取坐标并处理
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
检测用户是否在范围内。如果在短期内应用此方法,则此方法有效,但仅在应用程序暂停之前有效,即大约 3 分钟。理想情况下,我不想这么频繁地获取坐标。
区域监控:
我已经初始化了 CLLocationManager,如下所示:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
locationManager.delegate = self
locationManager.allowsBackgroundLocationUpdates = true
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.activityType = .otherNavigation
locationManager.requestAlwaysAuthorization()
}
LocationManager 在应用程序进入后台时启动:
func applicationDidEnterBackground(_ application: UIApplication) {
self.monitorRegionAtLocation(center: CLLocationCoordinate2D(latitude: x, longitude: y), identifier: id)
locationManager.startUpdatingLocation()
}
区域监控代码:
func monitorRegionAtLocation(center: CLLocationCoordinate2D, identifier: String ) {
// Make sure the app is authorized.
if CLLocationManager.authorizationStatus() == .authorizedAlways {
// Make sure region monitoring is supported.
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
// Register the region.
let maxDistance = 200.0
let region = CLCircularRegion(center: center,
radius: maxDistance, identifier: identifier)
region.notifyOnEntry = true
region.notifyOnExit = false
locationManager.startMonitoring(for: region)
}
}
}
并且我为 CLLocationManager 添加了一个 didEnterRegion 功能块:
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
if let region = region as? CLCircularRegion {
let identifier = region.identifier
print("FOUND: " + identifier)
}
}
该代码似乎可用于检测进入某个区域,但坐标不会在后台更新。
附加信息
- 我启用了位置更新和后台获取的后台模式
- 我在 Info.plist 中提供了 'Location Always Usage Description' 和 'Location When in Use Usage Description' 的值
- 应用程序设置显示 'Always' 对位置 的权限
我相信一定有更好的方法在后台进行这些类型的检查,但我还没有发现任何在后台检测其他动作的方法。
任何有关此事的指导将不胜感激,如果您需要更多信息,请告诉我,我会尽力提供。
更新:
我已经按照下面评论的建议修改了使用区域监控的方法。
题目说"CLLocationManager Region Monitoring: Detect Arrival in Background"。这是很有可能的,但是在被杀死后检测任何东西是不可能的(来自iOS 7)。
每当用户向上滑动您的应用程序应用程序切换器时,iOS 认为它是因为用户不希望该应用程序 运行 在后台运行,因此所有回调都是停止了。
This answer, this answer and this answer also says the same thing. However Apple doc有点乱。
我个人的观察是,即使在 Killed 模式下,应用程序也会被调用,但很少见。
关于获取位置,只要调用geofencing的delegate方法,就可以轻松获取位置。
而且您的要求确实不需要背景模式。
不幸的是(幸运的是 iOS 用户,因为他们节省了电池电量)我们真的没有办法在应用程序被杀死后的 1 小时内获取位置。
任何位置 update/monitoring 都需要正确配置其位置管理器,以便它能够以最佳状态提供所需的位置更新。在进行后台位置更新时检查一些点很重要:
1.检查位置更新和后台获取的后台模式应该启用
2。检查'Location Always Usage Description'和'Location When in Use Usage Description'中的Info.plist应提供
3。检查您是否想在位置更新之间暂停 - 如果是,那么您需要提供 activity 类型,以便位置管理员可以确定为您暂停位置更新的最佳方式
4。检查您是否要应用距离过滤器 - 您希望用户(设备)移动一些最小量以便位置管理器发送更新的位置
5.检查您是否需要所需的精度-这可能会导致某些精度类型的功耗
在您的代码中,我可以看到位置管理器配置了一些参数,但缺少后台模式的精度和距离过滤器。
locationManager.allowsBackgroundLocationUpdates = true
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.activityType = .otherNavigation
此外,如果您在 Apple doc 中看到暂停位置更新 属性,它表示:
For apps that have in-use authorization, a pause to location updates ends access to location changes until the app is launched again and able to restart those updates. If you do not wish location updates to stop entirely, consider disabling this property and changing location accuracy to kCLLocationAccuracyThreeKilometers when your app moves to the background. Doing so allows you to continue receiving location updates in a power-friendly manner.
本质上它告诉你,如果你想禁用暂停,那么你必须保持精度级别 (kCLLocationAccuracyThreeKilometers)。我猜你的方法中缺少这一点。
此外,您可以检查 this link 实际启动后台任务,然后在后台任务中启动位置管理器监控。 希望对你有帮助。