英文:
iOS: make "Location" appear in the app settings without requesting for location authorization (Tile app example)
问题
以下是翻译的部分:
长话短说:
我想在应用程序设置中显示“位置”,而不需要请求位置授权,就像Tile应用程序一样。
重现步骤:
- 安装Tile应用程序。
- 在应用程序设置中没有“位置”选项。
- 打开应用程序,接受蓝牙访问请求(这是否重要?)。
- 在应用程序设置中仍然没有“位置”选项,但蓝牙已出现。
- 使用应用程序约20秒钟(不能更短)。
- “位置”出现在应用程序设置中 - 如何做到的?
以下是视频演示:
https://media.giphy.com/media/h5dPQPbBHzEhdLTrKz/giphy.gif
我该如何实现这一点?
背景 - 为什么
自iOS 13以来,不能直接要求用户授予“始终”位置授权。当开发人员请求“始终”授权时,用户只能选择“仅在使用中”选项,应用程序获得“暂时始终”授权。在用户再次提示之前(由iOS决定何时),用户将在应用程序设置中看到“仅在使用中”授权。
这意味着:
-
始终
-->CLAuthorizationStatus.authorizedAlways
和应用程序设置中的始终
。 -
暂时始终
--> 也是CLAuthorizationStatus.authorizedAlways
,但在应用程序设置中是仅在使用中
。
这在此Stack Overflow答案中有很好的描述。
问题是应用程序无法在后台读取位置而不需要始终
授权(可以,但只能持续5-10秒),这极大地限制了某些应用程序的主要功能(例如iBeacon跟踪器)。
一个众所周知的做法是检查应用程序是否具有始终
授权,如果没有,提供信息描述为何这很重要以及用户如何更改它(在设置中手动更改)。
但是我们无法区分是否具有始终
或暂时始终
授权状态(至少不是直接),因此以下逻辑:
if (CLLocationManager.authorizationStatus() != .authorizedAlways) {
// 提示用户在设置中手动更改位置访问为始终
}
对于暂时始终
授权状态将无效。
解决方案可能是在请求位置授权之前要求用户在设置中手动选择始终
。我曾认为这是不可能的,除非首先调用requestAlwaysAuthorization()
,但Tile以某种方式做到了,如前面的视频所示。
更新:
我已经在Info.plist文件中设置了以下隐私键:
NSLocationAlwaysAndWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
英文:
Long story short:
I'd like to make "Location" appear in the app settings without requesting for location authorization, like the Tile app does.
Steps to reproduce:
- Install the Tile app.
- There is no "Location" in the app settings.
- Open the app, accept Bluetooth access request (does it matter?).
- There is still no "Location" in the app settings, but Bluetooth appears.
- Use the app for about 20 seconds (can't be shorter).
- "Location" appears in the app settings - how?
This is presented on the video below:
https://media.giphy.com/media/h5dPQPbBHzEhdLTrKz/giphy.gif
How can I achieve this?
Background - why
Since iOS 13, the user cannot be asked for Always
location authorization directly. When the developer requests for Always
authorization, the user can select only While in Use
option and the app gets Provisional Always
authorization. Until the user is prompted again (iOS decides when), the user will see While in Use
authorization in the app settings.
Which means:
-
Always
-->CLAuthorizationStatus.authorizedAlways
andAlways
in the app settings. -
Provisional Always
--> alsoCLAuthorizationStatus.authorizedAlways
butWhile in Use
in the app settings.
This is well described in this Stack Overflow answer.
The problem is that the application cannot read the location in the background without Always
authorization (it can, but only for 5-10 seconds), which greatly limits the main functionality of some apps (e.g. iBeacon trackers).
A well-known practice is to check if the app has Always
authorization, and if not, present information describing why this is important and how the user can change it (manually in settings).
But we cannot distinguish if we have Always
or Provisional Always
authorization status (at least directly), so the logic:
if (CLLocationManager.authorizationStatus() != .authorizedAlways) {
// Prompt the user to change Location access to Always manually in settings
}
will not work for Provisional Always
authorization status.
The solution could be to ask the user to choose Always
manually in the settings before requesting location authorization, to prevent Provisional Always
state from happening. I thought it was impossible without calling requestAlwaysAuthorization()
first, but Tile somehow does it, as presented on the previous video.
Update:
I already have:
NSLocationAlwaysAndWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
privacy keys set in Info.plist file.
答案1
得分: 0
你尝试过只是在你的 plist 文件中添加 NSLocationAlwaysAndWhenInUseUsageDescription
键,然后实例化一个 CLLocationServices
实例,并尝试启动位置更新吗?我怀疑这将导致该条目出现在设置中,即使在授予权限之前位置更新可能不会起作用。
英文:
Have you tried simply putting the NSLocationAlwaysAndWhenInUseUsageDescription
key in your plist and then instantiating a CLLocationServices
instance and using it to try to start a location update? I suspect this will cause the entry to appear in settings even if the location update will not function until permission is granted.
答案2
得分: 0
要在应用程序设置中显示“位置”而无需首先请求权限(“始终”需要两步操作),您需要调用locationManager.requestLocation()
。
func scheduleLocationUpdates() {
if CLLocationManager.locationServicesEnabled() && CLLocationManager.authorizationStatus() == .authorizedAlways {
locationManager.startUpdatingLocation()
// 隐藏全屏指示(如果已显示)
} else {
if (UIDevice.current.systemVersion as NSString).floatValue >= 13.0 {
locationManager.requestLocation() // 在仅适用于iOS 13上显示“位置”在应用程序设置中
// 显示全屏指示如何提供“始终授权”
} else {
if CLLocationManager.authorizationStatus() == .notDetermined {
locationManager.requestAlwaysAuthorization()
} else {
// 显示全屏指示如何提供“始终授权”
}
}
}
}
函数scheduleLocationUpdates()
应在viewWillAppear
中调用,并在UIApplication.willEnterForegroundNotification
事件之后调用(例如,当用户从设置返回时)。
在iOS 12上,“位置”将不会在未经许可的情况下出现在应用程序设置中。 但是,您可以直接请求“始终”权限(而不需要两个步骤),因此这是不必要的。
英文:
To reveal "Location" in the app settings without asking for permission first (Always
requires two-step opt-in), you need to call locationManager.requestLocation()
.
func scheduleLocationUpdates() {
if CLLocationManager.locationServicesEnabled() && CLLocationManager.authorizationStatus() == .authorizedAlways {
locationManager.startUpdatingLocation()
// hide full screen instruction (if shown)
} else {
if (UIDevice.current.systemVersion as NSString).floatValue >= 13.0 {
locationManager.requestLocation() // reveal "Location" in app settings (works on iOS 13 only)
// show full screen instruction how to provide "Always authorization"
} else {
if CLLocationManager.authorizationStatus() == .notDetermined {
locationManager.requestAlwaysAuthorization()
} else {
// show full screen instruction how to provide "Always authorization"
}
}
}
}
Function scheduleLocationUpdates()
should called in viewWillAppear
and after UIApplication.willEnterForegroundNotification
event (e.g. when the user comes back from Settings).
On iOS 12 "Location" will not appear in the app settings without asking for the permission first. But you can ask for Always
permission directly (without two steps), so this is not necessary.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论