如何在 iOS 应用中强制访问 'always' 位置信息
How to force 'always' location access in iOS app
我正在构建的应用程序始终需要位置访问权限才能正常工作。该应用程序基本上可以跟踪位置并将其放在地图上和其他东西上(细节不重要,哈哈)。
我的目标是:
- 提示用户启用“始终”位置访问
- 如果总是请求位置访问但用户拒绝,则让应用程序无法使用 - 基本上只显示一个小按钮,将他们重定向到可以更改该设置的设置。
我的AppDelegate.swift实现的是CLLocationManagerDelegate,代码如下:
alreadyRequestedLocationWhenInUse = UserDefaults.standard.bool(forKey: "alreadyRequestedLocationWhenInUse")
alreadyRequestedLocationAlways = UserDefaults.standard.bool(forKey: "alreadyRequestedLocationAlways")
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
if (!alreadyRequestedLocationWhenInUse) {
print("Requesting location access 'while in use'.")
self.locationManager.requestWhenInUseAuthorization();
UserDefaults.standard.set(true, forKey: "alreadyRequestedLocationWhenInUse")
alreadyRequestedLocationWhenInUse = true
} else {
promptToChangeLocationSettings()
}
case .restricted, .denied:
print("No Location access")
promptToChangeLocationSettings()
break;
case .authorizedWhenInUse:
if (!alreadyRequestedLocationAlways) {
print("Requesting location access 'Always'.")
self.locationManager.requestAlwaysAuthorization()
UserDefaults.standard.set(true, forKey: "alreadyRequestedLocationAlways")
alreadyRequestedLocationAlways = true
} else {
promptToChangeLocationSettings()
}
break;
case .authorizedAlways:
self.startLocationMonitoring();
break;
default:
self.locationManager.requestAlwaysAuthorization();
return
}
}
其中 promptToChangeLocationSettings() 是一个正常工作的函数,它将用户带到我的应用程序的设置页面。
问题是在用户退出应用程序并返回之前,不会提示用户启用“始终位置跟踪”。他们被要求获得 'while in use' 权限(我知道它的工作方式是他们必须先同意),但我希望始终提示立即发生!理论上,locationManagerDidChangeAuthorization 函数应该在授予 'while use' 授权后再次调用,但这并没有发生!为什么这不会发生?相反,promptUserToChangeLocationSettings() 在用户收到询问他们是否要启用 'always' 位置访问的小弹出窗口之前运行并使应用程序无法使用。
有人可以帮我解决这个问题吗?
顺便说一句,我正在使用 UserDefaults 来跟踪我们是否进行了位置权限请求(因为该请求只能进行一次)。
关于此流程的一些观察,我们首先请求“使用时”,当获得批准后,才请求“始终”(如 WWDC 2020 What's New in Location 中所述):
确保您 运行 这是在设备上,而不是模拟器上。使用模拟器时,您可能看不到随后的“将‘when-in-use’升级为‘始终’”权限警报。
此功能是在 iOS 13.4 中引入的。确保您没有在较早的 iOS 13 版本上尝试此操作。在那些较早的版本上,您不会看到升级到“始终”的第二个警报。
确保您的 code-base 其他地方没有挥之不去的 requestAlwaysAuthorization
可能会使应用程序处于“临时始终”状态。一旦进入临时状态,您将被锁定在 13.0 的临时流程中。
我知道这不是你要找的,但为了未来的读者,上述的替代方案是 iOS 13.0 中引入的更简单的“临时始终”流程(概述WWDC 2019 的 What's New in Core Location)。您只需调用 requestAlwaysAuthorization
(永远不会调用 requestWhenInUseAuthorization
)。 Apple 的目的是让用户更好地了解正在发生的事情,在应用程序正在使用时显示“使用时”警报,并在应用程序未使用定位服务时自动显示“始终”升级警报 运行宁.
这是一个得到我想要的结果的解决方案:
首先:在 AppDelegate.swift didFinishLaunchingWithOptions 函数中调用 locationManagerDidChangeAuthorization(locationManager) 。我还在 applicationWillEnterForeground 中调用它,以便每次打开应用程序时重新检查。
其次,这是我的新 locationManagerDidChangeAuthorization 函数。只需要删除 return/break 语句,但在我忘记之前我现在要回答这个问题:
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
UserDefaults.standard.set(false, forKey: "alreadyRequestedAlwaysLocationAccess")
alreadyRequestedAlwaysLocationAccess = false
DispatchQueue.main.async{
self.coreLocationManager.requestWhenInUseAuthorization()
self.locationManagerDidChangeAuthorization(manager)
}
break;
case .restricted, .denied:
print("No Location access")
promptToChangeLocationSettings()
break;
case .authorizedWhenInUse:
if (!alreadyRequestedAlwaysLocationAccess) {
print("Requesting location access 'Always'.")
UserDefaults.standard.set(true, forKey: "alreadyRequestedAlwaysLocationAccess")
alreadyRequestedAlwaysLocationAccess = true
DispatchQueue.main.async{
self.coreLocationManager.requestAlwaysAuthorization()
self.locationManagerDidChangeAuthorization(manager)
}
} else {
promptToChangeLocationSettings()
}
break;
case .authorizedAlways:
self.startLocationMonitoring();
break;
default:
return
}
}
我正在构建的应用程序始终需要位置访问权限才能正常工作。该应用程序基本上可以跟踪位置并将其放在地图上和其他东西上(细节不重要,哈哈)。
我的目标是:
- 提示用户启用“始终”位置访问
- 如果总是请求位置访问但用户拒绝,则让应用程序无法使用 - 基本上只显示一个小按钮,将他们重定向到可以更改该设置的设置。
我的AppDelegate.swift实现的是CLLocationManagerDelegate,代码如下:
alreadyRequestedLocationWhenInUse = UserDefaults.standard.bool(forKey: "alreadyRequestedLocationWhenInUse")
alreadyRequestedLocationAlways = UserDefaults.standard.bool(forKey: "alreadyRequestedLocationAlways")
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
if (!alreadyRequestedLocationWhenInUse) {
print("Requesting location access 'while in use'.")
self.locationManager.requestWhenInUseAuthorization();
UserDefaults.standard.set(true, forKey: "alreadyRequestedLocationWhenInUse")
alreadyRequestedLocationWhenInUse = true
} else {
promptToChangeLocationSettings()
}
case .restricted, .denied:
print("No Location access")
promptToChangeLocationSettings()
break;
case .authorizedWhenInUse:
if (!alreadyRequestedLocationAlways) {
print("Requesting location access 'Always'.")
self.locationManager.requestAlwaysAuthorization()
UserDefaults.standard.set(true, forKey: "alreadyRequestedLocationAlways")
alreadyRequestedLocationAlways = true
} else {
promptToChangeLocationSettings()
}
break;
case .authorizedAlways:
self.startLocationMonitoring();
break;
default:
self.locationManager.requestAlwaysAuthorization();
return
}
}
其中 promptToChangeLocationSettings() 是一个正常工作的函数,它将用户带到我的应用程序的设置页面。
问题是在用户退出应用程序并返回之前,不会提示用户启用“始终位置跟踪”。他们被要求获得 'while in use' 权限(我知道它的工作方式是他们必须先同意),但我希望始终提示立即发生!理论上,locationManagerDidChangeAuthorization 函数应该在授予 'while use' 授权后再次调用,但这并没有发生!为什么这不会发生?相反,promptUserToChangeLocationSettings() 在用户收到询问他们是否要启用 'always' 位置访问的小弹出窗口之前运行并使应用程序无法使用。
有人可以帮我解决这个问题吗? 顺便说一句,我正在使用 UserDefaults 来跟踪我们是否进行了位置权限请求(因为该请求只能进行一次)。
关于此流程的一些观察,我们首先请求“使用时”,当获得批准后,才请求“始终”(如 WWDC 2020 What's New in Location 中所述):
确保您 运行 这是在设备上,而不是模拟器上。使用模拟器时,您可能看不到随后的“将‘when-in-use’升级为‘始终’”权限警报。
此功能是在 iOS 13.4 中引入的。确保您没有在较早的 iOS 13 版本上尝试此操作。在那些较早的版本上,您不会看到升级到“始终”的第二个警报。
确保您的 code-base 其他地方没有挥之不去的
requestAlwaysAuthorization
可能会使应用程序处于“临时始终”状态。一旦进入临时状态,您将被锁定在 13.0 的临时流程中。
我知道这不是你要找的,但为了未来的读者,上述的替代方案是 iOS 13.0 中引入的更简单的“临时始终”流程(概述WWDC 2019 的 What's New in Core Location)。您只需调用 requestAlwaysAuthorization
(永远不会调用 requestWhenInUseAuthorization
)。 Apple 的目的是让用户更好地了解正在发生的事情,在应用程序正在使用时显示“使用时”警报,并在应用程序未使用定位服务时自动显示“始终”升级警报 运行宁.
这是一个得到我想要的结果的解决方案: 首先:在 AppDelegate.swift didFinishLaunchingWithOptions 函数中调用 locationManagerDidChangeAuthorization(locationManager) 。我还在 applicationWillEnterForeground 中调用它,以便每次打开应用程序时重新检查。
其次,这是我的新 locationManagerDidChangeAuthorization 函数。只需要删除 return/break 语句,但在我忘记之前我现在要回答这个问题:
func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
switch CLLocationManager.authorizationStatus() {
case .notDetermined:
UserDefaults.standard.set(false, forKey: "alreadyRequestedAlwaysLocationAccess")
alreadyRequestedAlwaysLocationAccess = false
DispatchQueue.main.async{
self.coreLocationManager.requestWhenInUseAuthorization()
self.locationManagerDidChangeAuthorization(manager)
}
break;
case .restricted, .denied:
print("No Location access")
promptToChangeLocationSettings()
break;
case .authorizedWhenInUse:
if (!alreadyRequestedAlwaysLocationAccess) {
print("Requesting location access 'Always'.")
UserDefaults.standard.set(true, forKey: "alreadyRequestedAlwaysLocationAccess")
alreadyRequestedAlwaysLocationAccess = true
DispatchQueue.main.async{
self.coreLocationManager.requestAlwaysAuthorization()
self.locationManagerDidChangeAuthorization(manager)
}
} else {
promptToChangeLocationSettings()
}
break;
case .authorizedAlways:
self.startLocationMonitoring();
break;
default:
return
}
}