提问人:ozg 提问时间:6/5/2014 最后编辑:Alokozg 更新时间:7/27/2023 访问量:284432
定位服务在 iOS 8 中不起作用
Location Services not working in iOS 8
问:
我的应用在 iOS 7 上运行良好,但不适用于 iOS 8 SDK。
CLLocationManager
没有返回位置,而且我在“设置”->“定位服务”下也没有看到我的应用。我在谷歌上搜索了这个问题,但什么也没出现。可能出了什么问题?
答:
我最终解决了我自己的问题。
显然,在iOS 8 SDK中,在开始位置更新之前,需要(用于后台位置)或(仅在前台时进行位置)调用。requestAlwaysAuthorization
requestWhenInUseAuthorization
CLLocationManager
还需要或键入要在提示中显示的消息。添加这些解决了我的问题。NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
Info.plist
有关更广泛的信息,请查看:Core-Location-Manager-Changes-in-ios-8
评论
我带着同样的问题拔掉了我的头发。Xcode 给出错误:
尝试在不提示的情况下启动位置更新 位置授权。必须先打电话或先打电话。
MapKit
-[CLLocationManager requestWhenInUseAuthorization]
-[CLLocationManager requestAlwaysAuthorization]
但是,即使您实现了上述方法之一,它也不会提示用户,除非 info.plist 中有 或 的条目。NSLocationAlwaysUsageDescription
NSLocationWhenInUseUsageDescription
将以下行添加到 info.plist,其中字符串值表示需要访问用户位置的原因
<key>NSLocationWhenInUseUsageDescription</key>
<string>This application requires location services to work</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>This application requires location services to work</string>
我认为自从我在 Xcode 5 中开始这个项目以来,这些条目可能已经丢失了。我猜 Xcode 6 可能会为这些键添加默认条目,但尚未确认。
您可以在此处找到有关这两个设置的更多信息
评论
根据 Apple 文档:
- https://developer.apple.com/documentation/corelocation/requesting_permission_to_use_location_services
- https://developer.apple.com/documentation/corelocation/cllocationmanager/1620562-requestwheninuseauthorization
从 iOS 8 开始,应用的 Info.plist 文件中需要存在 或 键值。然后,在注册位置更新之前,还需要通过致电或根据需要向用户请求权限。然后,您在 Info.plist 中输入的字符串将显示在随后的对话框中。NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
[self.myLocationManager requestWhenInUseAuthorization]
[self.myLocationManager requestAlwaysAuthorization]
如果用户授予权限,则一切照常。如果他们拒绝权限,则不会通知代理位置更新。
评论
为确保它与 iOS 7 向后兼容,您应该检查用户运行的是 iOS 8 还是 iOS 7。例如:
#define IS_OS_8_OR_LATER ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
//In ViewDidLoad
if(IS_OS_8_OR_LATER) {
[self.locationManager requestAlwaysAuthorization];
}
[self.locationManager startUpdatingLocation];
评论
if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { ...
requestAlwaysAuthorization
if
[self.locationManager performSelector:@selector(requestAlwaysAuthorization)];
__IPHONE_OS_VERSION_MAX_ALLOWED
(#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
)
具有向后兼容性的解决方案:
SEL requestSelector = NSSelectorFromString(@"requestWhenInUseAuthorization");
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined &&
[self.locationManager respondsToSelector:requestSelector]) {
[self.locationManager performSelector:requestSelector withObject:NULL];
} else {
[self.locationManager startUpdatingLocation];
}
在 Info.plist 中设置 NSLocationWhenInUseUsageDescription 键
评论
locationManager: (CLLocationManager *)manager didFailWithError: (NSError *)error
具有向后兼容性的解决方案,不会产生 Xcode 警告:
SEL requestSelector = NSSelectorFromString(@"requestWhenInUseAuthorization");
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined &&
[self.locationManager respondsToSelector:requestSelector]) {
((void (*)(id, SEL))[self.locationManager methodForSelector:requestSelector])(self.locationManager, requestSelector);
[self.locationManager startUpdatingLocation];
} else {
[self.locationManager startUpdatingLocation];
}
在 .NSLocationWhenInUseUsageDescription
Info.plist
对于iOS版本11.0+:
在 .以及其他 2 个键。NSLocationAlwaysAndWhenInUseUsageDescription
Info.plist
评论
我的解决方案可以在 Xcode 5 中编译:
#ifdef __IPHONE_8_0
NSUInteger code = [CLLocationManager authorizationStatus];
if (code == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) {
// choose one request according to your business.
if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
[self.locationManager requestAlwaysAuthorization];
} else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) {
[self.locationManager requestWhenInUseAuthorization];
} else {
NSLog(@"Info.plist does not contain NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription");
}
}
#endif
[self.locationManager startUpdatingLocation];
评论
询问位置的旧代码在 iOS 8 中不起作用。您可以尝试以下方法进行位置授权:
- (void)requestAlwaysAuthorization
{
CLAuthorizationStatus status = [CLLocationManager authorizationStatus];
// If the status is denied or only granted for when in use, display an alert
if (status == kCLAuthorizationStatusAuthorizedWhenInUse || status == kCLAuthorizationStatusDenied) {
NSString *title;
title = (status == kCLAuthorizationStatusDenied) ? @"Location services are off" : @"Background location is not enabled";
NSString *message = @"To use background location you must turn on 'Always' in the Location Services Settings";
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title
message:message
delegate:self
cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Settings", nil];
[alertView show];
}
// The user has not enabled any location services. Request background authorization.
else if (status == kCLAuthorizationStatusNotDetermined) {
[self.locationManager requestAlwaysAuthorization];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) {
// Send the user to the Settings for this app
NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:settingsURL];
}
}
评论
- (void)startLocationManager
{
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.distanceFilter = kCLDistanceFilterNone; //whenever we move
locationManager.desiredAccuracy = kCLLocationAccuracyBest;
[locationManager startUpdatingLocation];
[locationManager requestWhenInUseAuthorization]; // Add This Line
}
并添加到您的 info.plist 文件
评论
在 iOS 8 中,您需要执行两项额外的操作才能使位置正常工作:向 Info.plist 添加一个密钥,并向位置管理器请求授权,要求它启动
信息.plist:
<key>NSLocationUsageDescription</key>
<string>I need location</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>I need location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>I need location</string>
将此添加到代码中
if (IS_OS_8_OR_LATER)
{
[locationmanager requestWhenInUseAuthorization];
[locationmanager requestAlwaysAuthorization];
}
评论
对于所有拥有多个 Info.plist 文件的人来说,这是一个小帮手......
find . -name Info.plist | xargs -I {} /usr/libexec/PlistBuddy -c 'Add NSLocationWhenInUseUsageDescription string' {}
它会将所需的标记添加到当前目录(和子文件夹)中的所有 Info.plist 文件。
另一个是:
find . -name Info.plist | xargs -I {} /usr/libexec/PlistBuddy -c 'Set NSLocationWhenInUseUsageDescription $YOURDESCRIPTION' {}
它会将您的描述添加到所有文件中。
在此之前,添加 iOS8 位置服务请求:[locationManager startUpdatingLocation];
if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
[locationManager requestAlwaysAuthorization];
编辑应用并添加包含将向用户显示的字符串值的键(例如,Info.plist
NSLocationAlwaysUsageDescription
We do our best to preserve your battery life.
)
如果您的应用仅在应用打开时才需要定位服务,请替换:
requestAlwaysAuthorization
with 和requestWhenInUseAuthorization
NSLocationAlwaysUsageDescription
跟。NSLocationWhenInUseUsageDescription
添加键或(后台 GPS 使用)与字符串要求在每个目标上使用 GPS。
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
info.plist
通过运行以下命令请求权限:
[self initLocationManager:locationManager];
在哪里:initLocationManager
// asks for GPS authorization on iOS 8
-(void) initLocationManager:(CLLocationManager *) locationManager{
locationManager = [[CLLocationManager alloc]init];
if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
[locationManager requestAlwaysAuthorization];
}
请记住,如果每个目标的键都不在键上,则应用不会询问用户。提供与 iOS 7 的兼容性,该方法保证未来的兼容性,而不仅仅是解决 iOS 7 和 8 的问题。info.plist
if
respondsToSelector:
要在iOS 8中访问用户位置,您必须添加,
NSLocationAlwaysUsageDescription in the Info.plist
这将要求用户提供获取其当前位置的权限。
// ** Don't forget to add NSLocationWhenInUseUsageDescription in MyApp-Info.plist and give it a string
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
// Check for iOS 8. Without this guard the code will crash with "unknown selector" on iOS 7.
if ([self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[self.locationManager requestWhenInUseAuthorization];
}
[self.locationManager startUpdatingLocation];
// Location Manager Delegate Methods
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
NSLog(@"%@", [locations lastObject]);
}
对于使用 Xamarin 的用户,我必须手动将密钥 NSLocationWhenInUseUsageDescription
添加到 info.plist,因为它在 Xamarin 5.5.3 Build 6 或 XCode 6.1 的下拉列表中不可用 - 仅在列表中,这导致它继续以静默方式失败。NSLocationUsageDescription
CLLocationManager
我正在开发一个升级到 iOS 8 的应用程序,但定位服务停止工作。您可能会在“调试”区域中遇到错误,如下所示:
Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
我做了侵入性最小的程序。首先将条目添加到您的 info.plist:NSLocationAlwaysUsageDescription
请注意,我没有填写此键的值。这仍然有效,我并不担心,因为这是一个内部应用程序。此外,已经有一个标题要求使用定位服务,所以我不想做任何多余的事情。
接下来,我为 iOS 8 创建了一个条件:
if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[_locationManager requestAlwaysAuthorization];
}
在此之后,调用该方法:locationManager:didChangeAuthorizationStatus:
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus: (CLAuthorizationStatus)status
{
[self gotoCurrenLocation];
}
现在一切正常。与往常一样,请查看文档。
- (void)viewDidLoad
{
[super viewDidLoad];
self.locationManager = [[CLLocationManager alloc] init];
self.locationManager.delegate = self;
if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]){
NSUInteger code = [CLLocationManager authorizationStatus];
if (code == kCLAuthorizationStatusNotDetermined && ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)] || [self.locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)])) {
// choose one request according to your business.
if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationAlwaysUsageDescription"]){
[self.locationManager requestAlwaysAuthorization];
} else if([[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSLocationWhenInUseUsageDescription"]) {
[self.locationManager requestWhenInUseAuthorization];
} else {
NSLog(@"Info.plist does not contain NSLocationAlwaysUsageDescription or NSLocationWhenInUseUsageDescription");
}
}
}
[self.locationManager startUpdatingLocation];
}
> #pragma mark - CLLocationManagerDelegate
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"didFailWithError: %@", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[errorAlert show];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
NSLog(@"didUpdateToLocation: %@", newLocation);
CLLocation *currentLocation = newLocation;
if (currentLocation != nil) {
longitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.longitude];
latitudeLabel.text = [NSString stringWithFormat:@"%.8f", currentLocation.coordinate.latitude];
}
}
在 iOS 8 中,您需要做两件额外的事情才能使位置正常工作: 添加 Info.plist 的密钥,并从该位置请求授权 经理要求它开始。有两个 Info.plist 键用于新的 位置授权。其中一个或两个密钥是必需的。如果 这两个键都不存在,您可以调用 startUpdatingLocation,但 位置管理器实际上不会启动。它不会发送失败 给委托的消息(因为它从未启动过,所以它不能 失败)。如果您添加一个或两个键但忘记了,它也会失败 显式请求授权。所以你需要做的第一件事 是将以下一个或两个键添加到 Info.plist 文件:
- NSLocationWhenInUseUsageDescription
- NSLocationAlwaysUsageDescription
这两个键都采用字符串
这是对您为什么需要定位服务的描述。您可以 输入一个字符串,例如“需要位置才能找出您所在的位置” 与 iOS 7 一样,可以在 InfoPlist.strings 文件中进行本地化。
Swift 开发人员的一个常见错误:
首先,确保将 或 的值添加到 plist 中。NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
如果您仍然没有看到请求授权的弹出窗口,请查看您是否将该行放在 View Controller 的方法中。如果你这样做了,那么即使你打电话,也不会显示任何内容。这是因为在 viewDidLoad 执行后,locationManager 变量将被释放(清除)。var locationManager = CLLocationManager()
viewDidLoad
locationManager.requestWhenInUseAuthorization()
解决方案是将该行定位在类方法的顶部。var locationManager = CLLocationManager()
对我来说,问题是作为私有的类是私有的,这阻止了所有委托方法的调用。我想这不是一个很常见的情况,但我想我会提到它,以防万一对任何人有帮助。CLLocationManagerDelegate
我在iOS 8.4,iPad mini 2中添加了这些键。它也有效。我没有在我的 .InfoPlist.strings
NSLocationWhenInUseUsageDescription
Info.plist
InfoPlist.strings:
"NSLocationWhenInUseUsageDescription" = "I need GPS information....";
它说,基于这个线程,可以在 InfoPlist.strings 中本地化。在我的测试中,这些键可以直接在文件中配置。as in iOS 7
InfoPlist.strings
因此,您需要做的第一件事是将以下>项中的一个或两个添加到 Info.plist 文件中:
- NSLocationWhenInUseUsageDescription
- NSLocationAlwaysUsageDescription
这两个键都采用一个字符串,该字符串描述了为什么 需要定位服务。您可以输入类似“位置是”位置是 需要找出你在哪里“,就像在 iOS 7 中一样,可以是 在 InfoPlist.strings 文件中本地化。
更新:
我认为@IOS
的方法更好。将 key 添加到空值,并将本地化字符串添加到 。Info.plist
InfoPlist.strings
让 Cocoa Keys 信息始终触手可及,以便进行这些更新,这里是链接:
享受。
这是ios 8的问题 将此添加到代码中
if (IS_OS_8_OR_LATER)
{
[locationmanager requestWhenInUseAuthorization];
[locationmanager requestAlwaysAuthorization];
}
和 info.plist:
<key>NSLocationUsageDescription</key>
<string>I need location</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>I need location</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>I need location</string>
评论
NSLocationUsageDescription
在 iOS8+ 上未使用
我在 iOS 9 中遇到类似的错误(使用 Xcode 7 和 Swift 2):
尝试在不提示位置授权的情况下启动 MapKit 位置更新。必须先调用 -[CLLocationManager requestWhenInUseAuthorization] 或 -[CLLocationManager requestAlwaysAuthorization]。
我正在学习教程,但导师使用的是 iOS 8 和 Swift 1.2。Xcode 7 和 Swift 2 中有一些变化。我找到了这段代码,它对我来说工作正常:
import UIKit
import MapKit
import CoreLocation
class MapViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
// MARK: Properties
@IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
}
// MARK: - Location Delegate Methods
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
self.mapView.setRegion(region, animated: true)
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Errors: " + error.localizedDescription)
}
}
最后,我把它放在info.plist中: Information 属性列表:NSLocationWhenInUseUsageDescription 值:应用需要员工的位置服务器
为了在 iOS 中访问用户的位置,您需要添加两个密钥,
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
添加到 Info.plist 文件中。
<key>NSLocationWhenInUseUsageDescription</key>
<string>Because I want to know where you are!</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Want to know where you are!</string>
请参见下图。
Objective-C 过程
请按照以下说明操作:
对于iOS 11
对于iOS 11,请看这个答案: iOS 11位置访问
您需要将两个密钥添加到 plist 中并提供一条消息,如下图所示:
1. NSLocationAlwaysAndWhenInUseUsageDescription
2. NSLocationWhenInUseUsageDescription
3. NSLocationAlwaysUsageDescription
对于 iOS 10 及更低版本:
NSLocationWhenInUseUsageDescription
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
if([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {
[locationManager requestWhenInUseAuthorization];
} else {
[locationManager startUpdatingLocation];
}
委托方法
#pragma mark - Lolcation Update
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error
{
NSLog(@"didFailWithError: %@", error);
UIAlertView *errorAlert = [[UIAlertView alloc]
initWithTitle:@"Error" message:@"Failed to Get Your Location" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[errorAlert show];
}
-(void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
{
switch (status) {
case kCLAuthorizationStatusNotDetermined:
case kCLAuthorizationStatusRestricted:
case kCLAuthorizationStatusDenied:
{
// Do some error handling
}
break;
default: {
[locationManager startUpdatingLocation];
}
break;
}
}
- (void)locationManager:(CLLocationManager *)manager
didUpdateLocations:(NSArray *)locations
{
CLLocation *location = [locations lastObject];
userLatitude = [NSString stringWithFormat:@"%f", location.coordinate.latitude];
userLongitude = [NSString stringWithFormat:@"%f", location.coordinate.longitude];
[locationManager stopUpdatingLocation];
}
快速程序
请按照以下说明操作:
对于iOS 11
对于iOS 11,请看一下这个答案: iOS 11位置访问
您需要在 plist 中添加两个键并提供一条消息,如下图所示:
1. NSLocationAlwaysAndWhenInUseUsageDescription
2. NSLocationWhenInUseUsageDescription
3. NSLocationAlwaysUsageDescription
对于 iOS 10 及更低版本:
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
//MARK- Update Location
func updateMyLocation() {
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers;
if locationManager.respondsToSelector(#selector(CLLocationManager.requestWhenInUseAuthorization)) {
locationManager.requestWhenInUseAuthorization()
}
else {
locationManager.startUpdatingLocation()
}
}
委托方法
//MARK: Location Update
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
NSLog("Error to update location :%@", error)
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .NotDetermined: break
case .Restricted: break
case .Denied:
NSLog("do some error handling")
break
default:
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last! as CLLocation
var latitude = location.coordinate.latitude
var longitude = location.coordinate.longitude
}
评论