我在iOS 7上运行良好的应用无法与iOS 8 SDK一起使用。
CLLocationManager
不会返回位置,并且在“设置” ->“ 位置服务”下也看不到我的应用程序。我对此问题进行了Google搜索,但没有发现任何问题。有什么事吗
我在iOS 7上运行良好的应用无法与iOS 8 SDK一起使用。
CLLocationManager
不会返回位置,并且在“设置” ->“ 位置服务”下也看不到我的应用程序。我对此问题进行了Google搜索,但没有发现任何问题。有什么事吗
Answers:
我最终解决了自己的问题。
显然,在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可能会为这些键添加默认条目,但尚未确认。
您可以在此处找到有关这两个设置的更多信息
为了确保它与iOS 7向后兼容,您应该检查用户运行的是iOS 8还是iOS7。例如:
#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)];
。也许这对其他人来说是显而易见的,但是花了我一段时间才弄清楚。我认为这是正确的解决方案,直到最终的Xcode 6发布。
__IPHONE_OS_VERSION_MAX_ALLOWED
(#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
)有条件地进行编译
- (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文件
根据Apple文档:
从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文件中:
这两个键都带一个字符串
这是为什么需要定位服务的说明。您可以输入一个字符串,例如“需要位置才能找到自己的位置”,就像在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添加一个密钥,并向位置管理器请求授权以要求其启动
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>
将此添加到您的代码
if (IS_OS_8_OR_LATER)
{
[locationmanager requestWhenInUseAuthorization];
[locationmanager requestAlwaysAuthorization];
}
Swift开发人员的一个常见错误:
首先,请确保您为NSLocationWhenInUseUsageDescription
或的值添加了一个值NSLocationAlwaysUsageDescription
。
如果您仍然没有看到弹出窗口要求授权,请查看是否将该行var locationManager = CLLocationManager()
放入View Controller的viewDidLoad
方法中。如果您这样做,那么即使您致电locationManager.requestWhenInUseAuthorization()
,也不会显示任何内容。这是因为在执行viewDidLoad之后,会释放(清除)locationManager变量。
解决方案是将行定位var locationManager = CLLocationManager()
在class方法的顶部。
在之前[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键
locationManager: (CLLocationManager *)manager didFailWithError: (NSError *)error
。但是,他确实忘记将startUpdatingLocation添加到if语句中,因此在他们接受或拒绝它之后,它实际上并没有调用startUpdateLocation。
具有向后兼容性的解决方案,不会产生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及更高版本:安装NSLocationAlwaysAndWhenInUseUsageDescription
在你的钥匙Info.plist
。以及其他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>
NSLocationUsageDescription
在iOS8 +上未使用
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
}
// ** 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]);
}
一个拥有多个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' {}
它将您的描述添加到所有文件。
我在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中访问用户位置。您需要添加两个键
NSLocationWhenInUseUsesDescription
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>
参见下图。
要求在每个目标的每个目标上使用GPS NSLocationWhenInUseUsageDescription
或NSLocationAlwaysUsageDescription
字符串添加密钥或(使用背景GPS)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];
}
请记住,如果info.plist
每个目标上的按键都不在,则应用不会询问用户。在if
提供兼容的iOS 7的respondsToSelector:
方法保证未来的兼容性,而不仅仅是解决问题为iOS 7和8。
我InfoPlist.strings
在iOS 8.4,iPad mini 2中添加了这些密钥。它也可以工作。我没有设置任何按键,比如NSLocationWhenInUseUsageDescription
,在我的Info.plist
。
InfoPlist.strings:
"NSLocationWhenInUseUsageDescription" = "I need GPS information....";
它说,基于该线程,as in iOS 7
可以在InfoPlist.strings中进行本地化。在我的测试中,这些键可以直接在file中配置InfoPlist.strings
。
因此,您需要做的第一件事是在Info.plist文件中添加一个或以下两个键:
- NSLocationWhenInUseUsesDescription
- NSLocationAlwaysUsageDescription
这两个键都带有一个字符串,该字符串描述了为什么需要定位服务。您可以输入类似“需要位置才能找到您所在的位置”之类的字符串,就像在iOS 7中一样,可以在InfoPlist.strings文件中进行本地化。
更新:
我认为@IOS
的方法更好。将key添加为Info.plist
空值,并将本地化的字符串添加到InfoPlist.strings
。