簡體   English   中英

定位服務在 iOS 8 中不起作用

[英]Location Services not working in iOS 8

我在 iOS 7 上運行良好的應用程序不適用於 iOS 8 SDK。

CLLocationManager不返回位置,我也沒有在“設置” ->“位置服務”下看到我的應用程序。 我對這個問題進行了谷歌搜索,但沒有任何結果。 可能有什么問題?

我最終解決了我自己的問題。

顯然在 iOS 8 SDK 中,在開始位置更新之前,需要在CLLocationManager上調用requestAlwaysAuthorization (用於后台位置)或requestWhenInUseAuthorization (僅在前台時定位)。

Info.plist還需要有NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription鍵,並在提示中顯示一條消息。 添加這些解決了我的問題。

在此處輸入圖片說明

有關更多信息,請查看: Core-Location-Manager-Changes-in-ios-8

我正在用同樣的問題拉我的頭發。 Xcode 給你錯誤:

嘗試在不提示位置授權的情況下啟動MapKit位置更新。 必須先調用-[CLLocationManager requestWhenInUseAuthorization]-[CLLocationManager requestAlwaysAuthorization]

但即使您實現了上述方法之一,它也不會提示用戶,除非 info.plist 中有NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription

將以下行添加到您的 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 文件中需要存在NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription鍵值。 然后還需要在注冊位置更新之前請求用戶的許可,根據您的需要調用[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 文件中:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

這兩個鍵都需要一個字符串

這是您需要定位服務的原因的描述。 您可以輸入類似“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 開發人員的一個常見錯誤:

首先確保為NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription添加一個值到 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.

如果您的應用僅在應用打開時才需要定位服務,請替換:

requestAlwaysAuthorizationrequestWhenInUseAuthorization

NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescription

我正在開發一個升級到 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

在此處輸入圖片說明 對於 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

}

對於那些使用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>

請參閱下圖。

Info.plist 圖像

  1. 添加鍵NSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription (背景 GPS 使用)和字符串,要求在每個目標的每個info.plist上使用 GPS。

  2. 通過運行請求許可:

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM