[英]Location Services not working in iOS 8
我在 iOS 7 上运行良好的应用程序不适用于 iOS 8 SDK。
CLLocationManager
不返回位置,我也没有在“设置” ->“位置服务”下看到我的应用程序。 我对这个问题进行了谷歌搜索,但没有任何结果。 可能有什么问题?
我最终解决了我自己的问题。
显然在 iOS 8 SDK 中,在开始位置更新之前,需要在CLLocationManager
上调用requestAlwaysAuthorization
(用于后台位置)或requestWhenInUseAuthorization
(仅在前台时定位)。
Info.plist
还需要有NSLocationAlwaysUsageDescription
或NSLocationWhenInUseUsageDescription
键,并在提示中显示一条消息。 添加这些解决了我的问题。
有关更多信息,请查看: 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 可能会为这些键添加默认条目,但尚未确认。
您可以在此处找到有关这两个设置的更多信息
为确保这与 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];
- (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 文件中需要存在NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
键值。 然后还需要在注册位置更新之前请求用户的许可,根据您的需要调用[self.myLocationManager requestWhenInUseAuthorization]
或[self.myLocationManager requestAlwaysAuthorization]
。 您在 Info.plist 中输入的字符串将显示在随后的对话框中。
如果用户授予权限,则一切照旧。 如果他们拒绝许可,则不会通知代表位置更新。
- (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 文件中:
这两个键都需要一个字符串
这是您需要定位服务的原因的描述。 您可以输入类似“Location is required to find your where you are”这样的字符串,就像在 iOS 7 中一样,可以在 InfoPlist.strings 文件中进行本地化。
我的解决方案可以在 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];
}
}
在 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];
}
Swift 开发人员的一个常见错误:
首先确保为NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
添加一个值到 plist。
如果您仍然没有看到请求授权的弹出窗口,请查看您是否将var locationManager = CLLocationManager()
放在视图控制器的viewDidLoad
方法中。 如果这样做,那么即使您调用locationManager.requestWhenInUseAuthorization()
,也不会显示任何内容。 这是因为在 viewDidLoad 执行后,locationManager 变量被释放(清除)。
解决方案是在类方法的顶部找到行var locationManager = CLLocationManager()
。
[locationManager startUpdatingLocation];
之前[locationManager startUpdatingLocation];
,添加一个 iOS8 位置服务请求:
if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
[locationManager requestAlwaysAuthorization];
编辑您的应用程序的Info.plist
并添加键NSLocationAlwaysUsageDescription
和将显示给用户的字符串值(例如, We do our best to preserve your battery life.
)
如果您的应用仅在应用打开时才需要定位服务,请替换:
requestAlwaysAuthorization
和requestWhenInUseAuthorization
和
NSLocationAlwaysUsageDescription
和NSLocationWhenInUseUsageDescription
。
我正在开发一个升级到 iOS 8 的应用程序,但位置服务停止工作。 您可能会在 Debug 区域中得到和错误,如下所示:
Trying to start MapKit location updates without prompting for location authorization. Must call -[CLLocationManager requestWhenInUseAuthorization] or -[CLLocationManager requestAlwaysAuthorization] first.
我做了最少侵入性的程序。 首先将NSLocationAlwaysUsageDescription
条目添加到您的 info.plist 中:
注意我没有填写这个键的值。 这仍然有效,我并不担心,因为这是一个内部应用程序。 另外,已经有一个标题要求使用位置服务,所以我不想做任何多余的事情。
接下来我为 iOS 8 创建了一个条件:
if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
[_locationManager requestAlwaysAuthorization];
}
在此之后locationManager:didChangeAuthorizationStatus:
方法被调用:
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus: (CLAuthorizationStatus)status
{
[self gotoCurrenLocation];
}
现在一切正常。 与往常一样,请查看文档。
具有向后兼容性的解决方案:
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 键
具有向后兼容性且不会产生 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];
}
在Info.plist
设置NSLocationWhenInUseUsageDescription
键。
对于 iOS 11.0+ 版本:在Info.plist
设置NSLocationAlwaysAndWhenInUseUsageDescription
键。 以及其他 2 个键。
这是 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>
要在 iOS 8 中访问用户位置,您必须添加,
NSLocationAlwaysUsageDescription in the Info.plist
这将要求用户获得获取其当前位置的权限。
Objective-C 过程遵循以下说明:
对于 iOS-11对于 iOS 11,请查看此答案: iOS 11 位置访问
需要将两个密钥添加到 plist 并提供如下图所示的消息:
1. NSLocationAlwaysAndWhenInUseUsageDescription
2. NSLocationWhenInUseUsageDescription
3. NSLocationAlwaysUsageDescription
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
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
}
对于那些使用Xamarin 的人,我必须手动将键NSLocationWhenInUseUsageDescription
添加到 info.plist 中,因为它在 Xamarin 5.5.3 Build 6 或 XCode 6.1 的下拉列表中不可用 - 只有NSLocationUsageDescription
在列表中,这导致了CLLocationManager
继续默默地失败。
对拥有多个 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' {}
它会将您的描述添加到所有文件中。
// ** 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]);
}
我在 iOS9 中遇到了类似的错误(使用 Xcode 7 和 Swift 2):尝试在不提示位置授权的情况下启动 MapKit 位置更新。 必须先调用 -[CLLocationManager requestWhenInUseAuthorization] 或 -[CLLocationManager requestAlwaysAuthorization]。 我正在学习教程,但导师使用的是 iOS8 和 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 中:信息属性列表: 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>
请参阅下图。
添加键NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
(背景 GPS 使用)和字符串,要求在每个目标的每个info.plist
上使用 GPS。
通过运行请求许可:
[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];
}
请记住,如果密钥不在每个目标的每个info.plist
,应用程序将不会询问用户。 if
提供与 iOS 7 的兼容性, respondsToSelector:
方法保证了未来的兼容性,而不仅仅是解决 iOS 7 和 8 的问题。
我的问题是CLLocationManagerDelegate
类是私有的,这阻止了所有委托方法被调用。 猜猜这不是一个很常见的情况,但我想我会提到它以防对任何人有帮助。
我在iOS 8.4、iPad mini 2 的InfoPlist.strings
中添加了这些键。它也能工作。 我没有在我的Info.plist
设置任何键,比如NSLocationWhenInUseUsageDescription
。
InfoPlist.strings :
"NSLocationWhenInUseUsageDescription" = "I need GPS information....";
它说, 基于这个线程, as in iOS 7
,可以在 InfoPlist.strings 中进行本地化。 在我的测试中,这些键可以直接在文件InfoPlist.strings
配置。
因此,您需要做的第一件事是将 > 以下键中的一个或两个添加到您的 Info.plist 文件中:
- NSLocationWhenInUseUsageDescription
- NSLocationAlwaysUsageDescription
这两个键都采用一个字符串,它描述了您为什么需要位置服务。 您可以输入类似“Location is required to find your where you are”这样的字符串,就像在iOS 7 中一样,可以在 InfoPlist.strings 文件中进行本地化。
更新:
我认为@IOS
的方法更好。 使用空值向Info.plist
添加键,并将本地化字符串添加到InfoPlist.strings
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.