บริการตำแหน่งไม่ทำงานใน iOS 8


608

แอพของฉันที่ทำงานได้ดีบน iOS 7 ไม่สามารถทำงานกับ iOS 8 SDK

CLLocationManagerไม่ส่งคืนตำแหน่งและฉันไม่เห็นแอปของฉันภายใต้การตั้งค่า -> บริการระบุตำแหน่ง ฉันทำการค้นหาโดย Google เกี่ยวกับปัญหานี้ แต่ไม่มีอะไรเกิดขึ้น มีอะไรผิดปกติ?


นอกจากนี้คุณยังสามารถใช้สิ่งนี้เป็นแอพอ้างอิงสำหรับการแก้ปัญหาgithub.com/jbanford/ConstantLocationUpdates
Ashok vadivelu

19
ฉันโพสต์เกี่ยวกับการเปลี่ยนแปลงตัวจัดการตำแหน่งใน iOS 8 ที่นี่: nevan.net/2014/09/core-location-manager-changes-in-ios-8
nevan king

2
คุณสามารถลองใช้ไลบรารีนี้ซึ่งช่วยลดความซับซ้อนของ Core Location APIs และเปิดเผยอินเตอร์เฟสที่ดีตามบล็อกและทำให้ความแตกต่างทั้งหมดระหว่าง iOS เวอร์ชันต่าง ๆ (เปิดเผยโดยสมบูรณ์: ฉันเป็นผู้เขียน): github.com/lmirosevic/GBLocation
lms

ฉันพบข้อมูลอ้างอิงบางส่วนได้ที่นี่datacalculation.blogspot.in/2014/11/…
การทดสอบ iOS

2
@Nevanking คุณครับ! ต้องการมงกุฎ! ฉันต่อสู้กับปัญหานี้มาตั้งแต่การเปลี่ยนแปลงและยังไม่พบ "แนวทาง" ในการแก้ไขนั่นเป็นมิตร noob .. คำแนะนำของคุณทำให้คนงี่เง่าเช่นฉันจัดการกับปัญหาของตัวเอง ขอบคุณมากสำหรับลิงค์นั้น
Patrick R

คำตอบ:


1086

ฉันลงเอยด้วยการแก้ปัญหาของตัวเอง

เห็นได้ชัดว่าใน iOS 8 SDK requestAlwaysAuthorization(สำหรับตำแหน่งพื้นหลัง) หรือrequestWhenInUseAuthorization(เฉพาะตำแหน่งที่อยู่ด้านหน้า) CLLocationManagerจะต้องทำการโทรก่อนที่จะเริ่มอัปเดตตำแหน่ง

นอกจากนี้ยังมีความต้องการที่จะNSLocationAlwaysUsageDescriptionหรือNSLocationWhenInUseUsageDescriptionสำคัญในการInfo.plistที่มีข้อความที่จะแสดงในพรอมต์ การเพิ่มสิ่งเหล่านี้ช่วยแก้ปัญหาของฉันได้

enter image description here

หวังว่ามันจะช่วยคนอื่น

แก้ไข: สำหรับข้อมูลเพิ่มเติมเพิ่มเติมดูได้ที่: Core-Location-Manager-Changes-in-ios-8


6
คุณสามารถแบ่งปันค่าที่แน่นอนที่อัพเดทใน Info.plist ได้หรือไม่? เอี่ยมไม่สามารถเห็นรหัสนั้นใน Info.plist ของฉันได้ ฉันเพิ่มและยังดูเหมือนว่าจะไม่ทำงาน ฉันใช้ Swift, iOS8 และ XCode 6 beta 4
Vijay Kumar AB

4
@Vjay - คุณต้องแก้ไขไฟล์ Info.plist ในโปรแกรมแก้ไขไม่สามารถตั้งค่าคีย์เหล่านั้นใน Xcode (ตั้งแต่เบต้า 6)
Kendall Helmstetter Gelner

11
เพียงเตือนความจำหากคุณไม่ต้องการแสดงคำอธิบายที่กำหนดเองให้กับผู้ใช้เพียงตั้งค่าคีย์นี้เป็นสตริงว่าง
ไม่ใช่

7
คุณต้องรักษาตำแหน่งผู้จัดการของคุณเพื่อให้มันทำงานได้ ดังนั้นให้ CLLocationManager ของคุณเป็นทรัพย์สินที่แข็งแกร่ง
Vassily

273
ฉัน 'รัก' ที่คุณจะได้รับไม่มีข้อผิดพลาดไม่มีการเตือนไม่มีข้อความบันทึกไม่มีอะไรถ้าคุณออกจากรายการ plist โดยทั่วไป Apple ได้สร้างการเรียก API ที่ไม่มีอะไรเกิดขึ้นถ้าคุณไม่มีรายการ plist ที่เหมาะสม ขอบคุณ @OrtwinGentz ​​สำหรับการหาสิ่งนี้
MobileVet

314

ฉันกำลังดึงผมออกด้วยปัญหาเดียวกัน 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 อาจเพิ่มรายการเริ่มต้นสำหรับคีย์เหล่านี้ แต่ยังไม่ได้รับการยืนยัน

คุณสามารถหาข้อมูลเพิ่มเติมเกี่ยวกับการตั้งค่าทั้งสองนี้ได้ที่นี่


13
xcode 6 ไม่ได้เพิ่มคีย์เหล่านี้ตามค่าเริ่มต้นหากคุณต้องการใช้งาน CLLocationManager คุณต้องเพิ่มด้วยตนเอง
Wesley Smith

1
ฉันยังต้องเพิ่มสิ่งเหล่านี้ด้วยตนเองไม่สามารถเพิ่มผ่านมุมมอง RawValues ​​ของ info.plist ใน Xcode6!
Kendall Helmstetter Gelner

1
ฉันดูตลอดไปสำหรับสิ่งนี้ ข้อความ [CLLLocationManager authenticationStatus] ของฉันส่งคืนค่า <nil> เท่านั้น หลังจากเพิ่มปุ่มด้านบนมันเริ่มคืนค่าที่เกี่ยวข้องสำหรับการส่งออกข้อความ จากสิ่งที่ ive พบว่าเป็นข้อบกพร่องของ iOS 8 ที่รู้จักกัน แต่ไม่สามารถหาอะไรในบริบทของฉันสำหรับทุกวัย ขอบคุณมาก!
MrOli3000

4
ฉันชอบค่าสตริงที่คุณใส่
Chris Chen

1
ข้อความจะปรากฏเป็นข้อความย่อยในการแจ้งเตือนที่ถามว่าผู้ใช้ต้องการแชร์ตำแหน่งของพวกเขาหรือไม่ ดังนั้นการว่างเปล่า (ว่างเปล่า) ดูเหมือนว่าเหมาะสมที่สุดในใบสมัครของฉัน คำอธิบายว่าทำไมคุณต้องการใช้ตำแหน่งก็สมเหตุสมผล อย่างไรก็ตาม NSLocationWhenInUseUsageDescription ไม่ได้ทำงานตามที่คาดไว้สำหรับฉัน (เช่น. ได้รับการอนุญาตที่ถูกปฏิเสธแม้ว่าค่าตอบแทนจะถูกต้อง) NSLocationAlwaysUsageDescription ทำงานได้ดี
อาร์เคียดบ๊อบ

104

เพื่อให้แน่ใจว่าสามารถใช้งานร่วมกับ 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];

164
วิธีที่ดีกว่าการตรวจสอบเวอร์ชั่นคือการตรวจสอบว่าวัตถุมีตัวเลือกนั้นหรือไม่เช่น: if ([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) { ...
progrmr

1
ฉันมีปัญหาในการใช้งานโซลูชันของ @ progrmr เมื่อสร้างบน Xcode 5 เนื่องจากไม่ทราบว่าrequestAlwaysAuthorizationวิธีการคืออะไร วิธีการแก้ปัญหาเพิ่มเติมของฉันคือการใช้สายนี้ในคำสั่งแทนการเรียกวิธีปกติ:if [self.locationManager performSelector:@selector(requestAlwaysAuthorization)];บางทีนี่อาจจะเป็นที่เห็นได้ชัดสำหรับคนอื่น ๆ แต่มันใช้เวลาพอสมควรที่จะคิดออก ฉันคิดว่ามันเป็นทางออกที่ถูกต้องจนกว่า Xcode 6 สุดท้ายจะวางจำหน่าย
VinceFior

2
ทางออกที่ถูกต้องคือการสร้างด้วย Xcode 6 หากคุณกำลังสร้างด้วย Xcode 5 คุณไม่จำเป็นต้องขออนุญาตมันเป็นแบบอัตโนมัติ
progrmr

คุณอาจมีประเด็น ความกังวลของฉันคือฉันต้องการให้โค้ดของฉันคอมไพล์ใน Xcode 5 (แม้ว่ามันจะไม่ทำงานบน iOS 8 ยกเว้นว่าคอมไพล์ใน Xcode 6) ในขณะที่ทีมของฉันเปลี่ยนไปเป็น Xcode 6 แต่อาจเป็นเวิร์กโฟลว์ที่ดีกว่า ไม่รวมมันจนกว่าเราจะย้ายไปที่ Xcode 6 .. ขอบคุณ
VinceFior

@VinceFior วิธีที่แนะนำคือการรวบรวมเงื่อนไขการใช้ SDK กำหนดมาโคร__IPHONE_OS_VERSION_MAX_ALLOWED( #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
สตีเฟนเครเมอ

50
- (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 ของคุณ ป้อนคำอธิบายรูปภาพที่นี่


1
พบวิธีแก้ปัญหาที่คล้ายกันในแบบอธิบายเพิ่มเติมที่datacalculation.blogspot.in/2014/11/…
การทดสอบ iOS

2
@Hemang: ตามเอกสารของ Apple Dev: การเริ่มบริการตำแหน่งจะปลอดภัยก่อนที่จะมีการกำหนดสถานะการอนุญาตของแอพของคุณ แม้ว่าคุณสามารถเริ่มบริการตำแหน่งบริการเหล่านั้นจะไม่ส่งข้อมูลใด ๆ จนกว่าสถานะการอนุญาตจะเปลี่ยนเป็น kCLAuthorizationStatusAuthorizedAlways หรือ kCLAuthorizationStatusAuthorizedWhenInUse
แอนดรู

สายไปหน่อย แต่ฉันขอแนะนำให้คุณซ่อนส่วนที่ไม่เกี่ยวข้องในไฟล์
Plist

ขอบคุณ แต่ thats เพียงตัวอย่างหุ่น :)
นีโอ D1

สิ่งสำคัญคือโครงการจะชี้ไปที่info.plist ที่ถูกต้อง (โครงการที่กำหนดคีย์) ที่กำหนดไว้ในการตั้งค่าการสร้างโครงการภายใต้ไฟล์ Info.plist
clearlight

30

ตามเอกสารของ Apple:

ตั้งแต่ iOS 8 ต้องมี a NSLocationWhenInUseUsageDescriptionหรือNSLocationAlwaysUsageDescriptionค่าคีย์ในไฟล์ Info.plist ของแอปของคุณ นอกจากนี้ยังจำเป็นต้องขออนุญาตจากผู้ใช้ก่อนที่จะลงทะเบียนเพื่ออัปเดตตำแหน่งไม่ว่าจะเป็นการโทร[self.myLocationManager requestWhenInUseAuthorization]หรือ[self.myLocationManager requestAlwaysAuthorization]ขึ้นอยู่กับความต้องการของคุณ สตริงที่คุณป้อนลงใน Info.plist จะปรากฏขึ้นในกล่องโต้ตอบที่ตามมา

หากผู้ใช้ให้สิทธิ์มันเป็นธุรกิจตามปกติ หากพวกเขาปฏิเสธการอนุญาตตัวแทนจะไม่ได้รับแจ้งการอัปเดตตำแหน่ง


ฉันพบคำอธิบายง่ายๆที่นี่ที่datacalculation.blogspot.in/2014/11/…
การทดสอบ iOS

28
- (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

ป้อนคำอธิบายรูปภาพที่นี่


19

โซลูชันของฉันซึ่งสามารถรวบรวมได้ใน 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];

2
โซลูชันแบบไดนามิกที่ดีที่จะใช้ในทุกแอพ ฉันจะเปลี่ยนลำดับและแทนที่จะตรวจสอบสำหรับ iphone 8.0 ฉันจะตรวจสอบว่าผู้จัดการสถานที่ตอบสนองต่อการอนุญาตแล้วเรียกใช้การอนุญาตตามปกติเพื่อรับรหัส สิ่งนี้จะทำให้เป็นสากลมากขึ้น
zirinisp

ทำงานบน xCode 7.2 เช่นกัน
Totoro

17

รหัสเก่าสำหรับการถามตำแหน่งจะไม่ทำงานใน 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];
    }
}

UIAlertView เลิกใช้แล้ว คุณควรใช้ UIAlertController แทน
Pasan Premaratne

ใช่ฉันรู้ว่ามันเลิกใช้แล้ว แต่มันก็ใช้ได้เหมือนกัน แต่ใช่ควรใช้ UIAlertController สำหรับ IOS8
Nits007ak

12

ใน 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];
}

1
ยังไม่ชัดเจนว่า pseudocode ของคุณคือการโทร preprocessor หรือการโทรปกติ
El Dude

1
เพิ่มสิ่งนี้ลงในไฟล์ค่าคงที่ของคุณหรือ. pch: #define IS_OS_8_OR_LATER ([[UIDevice currentDevice] .systemVersion floatValue]> = 8.0)
OxenBoxen

ทำไมคุณถึงร้องขอทั้งสองคุณควรเพิ่มความคิดเห็นที่กล่าวถึงเพียงเพื่อใช้อย่างใดอย่างหนึ่งขึ้นอยู่กับความต้องการใช้งานของคุณ
powerj1984

ส่วน info.plist นั้นง่ายพอที่จะทำใน Unity3d แต่ฉันจะเพิ่มส่วนของรหัสได้อย่างไรถ้าใช้ unity3d ที่ไหน
CthulhuJon

11

ข้อผิดพลาดทั่วไปหนึ่งข้อสำหรับนักพัฒนา Swift:

ทำให้แน่ใจว่าคุณแรกเพิ่มมูลค่าให้กับ plist สำหรับการอย่างใดอย่างหนึ่งหรือNSLocationWhenInUseUsageDescriptionNSLocationAlwaysUsageDescription

หากคุณยังไม่เห็นหน้าต่างปรากฏขึ้นเพื่อขอการอนุญาตให้ดูเพื่อดูว่าคุณวางบรรทัดvar locationManager = CLLocationManager()ในวิธีการของ View Controller viewDidLoadหรือไม่ ถ้าคุณทำเช่นนั้นแม้ว่าคุณจะโทรlocationManager.requestWhenInUseAuthorization()มา นี่เป็นเพราะหลังจากที่ viewDidLoad ดำเนินการตัวแปร locationManager จะถูกจัดสรรคืน

การแก้ปัญหาคือการหาบรรทัดvar locationManager = CLLocationManager()ที่ด้านบนของวิธีการเรียน


9

ก่อน[locationManager startUpdatingLocation];เพิ่มคำขอบริการระบุตำแหน่ง iOS8:

if([locationManager respondsToSelector:@selector(requestAlwaysAuthorization)])
    [locationManager requestAlwaysAuthorization];

แก้ไขแอปInfo.plistและเพิ่มคีย์NSLocationAlwaysUsageDescriptionด้วยค่าสตริงที่จะแสดงต่อผู้ใช้ (ตัวอย่างเช่นWe do our best to preserve your battery life. )

หากแอปของคุณต้องการบริการระบุตำแหน่งขณะที่แอปเปิดอยู่ให้แทนที่:

requestAlwaysAuthorizationด้วยrequestWhenInUseAuthorizationและ

NSLocationAlwaysUsageDescriptionNSLocationWhenInUseUsageDescriptionกับ


9

ฉันทำงานกับแอพที่อัปเกรดเป็น 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];
}

และตอนนี้ทุกอย่างทำงานได้ดี และเช่นเคยตรวจสอบเอกสาร


7

โซลูชันที่มีความเข้ากันได้แบบย้อนหลัง:

SEL requestSelector = NSSelectorFromString(@"requestWhenInUseAuthorization");
if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined &&
    [self.locationManager respondsToSelector:requestSelector]) {
    [self.locationManager performSelector:requestSelector withObject:NULL];
} else {
    [self.locationManager startUpdatingLocation];
}

ตั้งค่าคีย์ NSLocationWhenInUseUsageDescription ใน Info.plist ของคุณ


2
สิ่งนี้ไม่ถูกต้องสิ่งที่เกี่ยวกับกรณี kCLAuthorizationStatusDenied? มันกระโดดไปที่อื่นและเริ่มอัปเดตตำแหน่งที่ไม่ถูกต้อง!
electronix384128

@ BenMarten ฉันไม่คิดว่ามันจะเป็นเรื่องสำคัญ locationManager: (CLLocationManager *)manager didFailWithError: (NSError *)errorคุณควรจะจัดการกับตัวเองว่า อย่างไรก็ตามเขาลืมเพิ่ม startUpdatingLocation ไปที่คำสั่ง if ดังนั้นหลังจากที่พวกเขายอมรับหรือปฏิเสธมันก็ไม่ได้เรียก startUpdateLocation
Chris

6

โซลูชันที่มีความเข้ากันได้แบบย้อนกลับซึ่งไม่ได้สร้างคำเตือน 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];
}

การตั้งค่าที่สำคัญในของคุณNSLocationWhenInUseUsageDescriptionInfo.plist

สำหรับ iOS เวอร์ชัน 11.0 ขึ้นไปติดตั้งที่สำคัญในของคุณNSLocationAlwaysAndWhenInUseUsageDescription Info.plistพร้อมกับปุ่มอื่น ๆ 2 ปุ่ม


สิ่งนี้ไม่ถูกต้องสิ่งที่เกี่ยวกับกรณี kCLAuthorizationStatusDenied? มันกระโดดไปที่อื่นและเริ่มอัปเดตตำแหน่งที่ไม่ถูกต้อง!
electronix384128

มันค่อนข้างแปลก, มันใช้งานได้ดีสำหรับฉันไม่ได้ดีอย่างสมบูรณ์แบบด้วยทั้งอนุญาตและไม่อนุญาตโซลูชันของ Jacob แม้จะดูแม่นยำ แต่ก็ไม่ได้ผลสำหรับฉัน แปลก แต่ใช้งานได้ !!!
josh

โทร [self.locationManager เริ่มต้นการอัปเดตตำแหน่ง] ได้ทันทีหลังจากมีการร้องขอเมื่อ InnInUseAuthorization ไม่มีประเด็น
Kostia Kim

5

นี่เป็นปัญหากับ 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 +
Carlos Ricardo

4

ในการเข้าถึงตำแหน่งผู้ใช้ใน iOS 8 คุณจะต้องเพิ่ม

NSLocationAlwaysUsageDescription in the Info.plist 

การดำเนินการนี้จะขอให้ผู้ใช้รับสิทธิ์ในการรับตำแหน่งปัจจุบัน


4

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

}

โปรดตรวจสอบให้แน่ใจว่าได้เพิ่ม NSLocationAlwaysUsageDescription แล้วมิฉะนั้นคุณจะได้รับข้อผิดพลาดขณะอัปโหลดที่ app store
Alok

ข้อความของคุณควรเป็นข้อมูลมิฉะนั้นแอปเปิ้ลจะปฏิเสธแอปในขณะกระบวนการ reviwing
Alok

3

สำหรับผู้ที่ใช้Xamarinฉันต้องเพิ่มคีย์NSLocationWhenInUseUsageDescriptionไปที่ info.plist ด้วยตนเองเนื่องจากไม่สามารถใช้งานได้ในรายการแบบเลื่อนลงทั้งใน Xamarin 5.5.3 Build 6 หรือ XCode 6.1 - มี NSLocationUsageDescriptionอยู่ในรายการเท่านั้นและนั่นทำให้CLLocationManagerต้องดำเนินการต่อไป ล้มเหลวอย่างเงียบ ๆ


2
        // ** 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]);

}

2

ผู้ช่วยเล็ก ๆ น้อย ๆ สำหรับคุณทุกคนที่มีไฟล์ 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' {} 

มันจะเพิ่มคำอธิบายของคุณไปยังไฟล์ทั้งหมด



2

ฉันได้รับข้อผิดพลาดที่คล้ายกันใน 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 Value: แอปต้องการเซิร์ฟเวอร์ตำแหน่งที่ตั้งสำหรับพนักงาน


2

เพื่อเข้าถึงตำแหน่งผู้ใช้ใน 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
  1. เพิ่มคีย์NSLocationWhenInUseUsageDescriptionหรือNSLocationAlwaysUsageDescription(ใช้พื้นหลัง GPS) ด้วยสตริงที่ขอให้ใช้ GPS ในinfo.plistแต่ละเป้าหมาย

  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


0

ปัญหาสำหรับฉันคือคลาสที่CLLocationManagerDelegateเป็นแบบส่วนตัวซึ่งป้องกันไม่ให้วิธีการมอบหมายทั้งหมดถูกเรียก คิดว่ามันไม่ใช่สถานการณ์ทั่วไป แต่คิดว่าฉันจะพูดถึงมันในกรณีที่ไม่ช่วยใคร


0

ฉันเพิ่มคีย์เหล่านั้นInfoPlist.stringsในiOS 8.4, iPad mini 2มันใช้ได้เช่นกัน ผมไม่ได้ตั้งค่าใด ๆ ที่สำคัญเช่นในของฉันNSLocationWhenInUseUsageDescriptionInfo.plist


InfoPlist.strings :

"NSLocationWhenInUseUsageDescription" = "I need GPS information....";

ฐานของเธรดนี้กล่าวว่าas in iOS 7สามารถแปลเป็นภาษาท้องถิ่นใน InfoPlist.strings InfoPlist.stringsในการทดสอบของฉันคีย์เหล่านั้นสามารถกำหนดค่าได้โดยตรงในแฟ้ม

ดังนั้นสิ่งแรกที่คุณต้องทำคือการเพิ่มปุ่ม> ต่อไปนี้หนึ่งปุ่มหรือทั้งสองอย่างลงในไฟล์ Info.plist ของคุณ:

  • NSLocationWhenInUseUsageDescription
  • NSLocationAlwaysUsageDescription

คีย์ทั้งสองนี้ใช้สายอักขระซึ่งเป็นคำอธิบายว่าทำไมคุณจึงต้องใช้บริการระบุตำแหน่ง คุณสามารถป้อนสตริงเช่น“ ต้องระบุตำแหน่งเพื่อค้นหาว่าคุณอยู่ที่ไหน” ซึ่งในiOS 7สามารถแปลเป็นภาษาท้องถิ่นได้ในไฟล์ InfoPlist.strings


UPDATE:

ฉันคิดว่า@IOSวิธีการนั้นดีกว่า เพิ่มคีย์ไปที่Info.plistมีค่าว่างและเพิ่มสตริงที่โลคัลInfoPlist.stringsไลซ์แล้ว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.