[英]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.