iOS 7で問題なく動作した私のアプリは、iOS 8 SDKでは動作しません。
CLLocationManager
位置情報が返されず、[設定] -> [ 位置情報サービス]にもアプリが表示されません。この問題についてGoogleで検索しましたが、何も見つかりませんでした。何が悪いのでしょうか?
iOS 7で問題なく動作した私のアプリは、iOS 8 SDKでは動作しません。
CLLocationManager
位置情報が返されず、[設定] -> [ 位置情報サービス]にもアプリが表示されません。この問題についてGoogleで検索しましたが、何も見つかりませんでした。何が悪いのでしょうか?
回答:
私は自分の問題を解決することになりました。
どうやら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でこのプロジェクトを開始してからこれらのエントリが欠落している可能性があると思います。Xcode6がこれらのキーのデフォルトエントリを追加する可能性があると思いますが、確認していません。
これら2つの設定の詳細については、こちらをご覧ください。
これが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];
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ファイルに
アップルのドキュメントによると:
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では、位置情報を機能させるために、次の2つのことを行う必要があります。Info.plistにキーを追加し、位置情報マネージャに開始を要求する承認を要求します。新しい位置認証のための2つのInfo.plistキーがあります。これらのキーの一方または両方が必要です。どちらのキーもない場合は、startUpdatingLocationを呼び出すことができますが、ロケーションマネージャーは実際には起動しません。デリゲートに失敗メッセージを送信することもありません(開始されていないため、失敗することはありません)。また、一方または両方のキーを追加したが、明示的に承認を要求し忘れた場合も失敗します。したがって、最初に行う必要があるのは、次のキーの1つまたは両方を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では、位置情報を機能させるために、次の2つのことを行う必要があります。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開発者によくあるエラーの1つ:
最初に、NSLocationWhenInUseUsageDescription
またはのいずれかの値をplistに追加してくださいNSLocationAlwaysUsageDescription
。
あなたがいる場合は、まだウィンドウが承認を求めポップアップ表示を見ていない、あなたがラインを入れているかどうかを確認しますvar locationManager = CLLocationManager()
あなたのビューコントローラの中でviewDidLoad
メソッド。その場合、を呼び出してlocationManager.requestWhenInUseAuthorization()
も何も表示されません。これは、viewDidLoadの実行後、locationManager変数の割り当てが解除される(クリアされる)ためです。
解決策はvar locationManager = CLLocationManager()
、クラスメソッドの上部に行を配置することです。
の前[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にアップグレードされたアプリで作業していて、位置情報サービスが機能しなくなりました。おそらく、次のようにデバッグ領域でエラーが発生します。
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
です。ただし、ifステートメントにstartUpdatingLocationを追加するのを忘れていたため、受諾または拒否した後、実際には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の位置情報アクセス
2つのキーを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の位置情報アクセス
2つのキーを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でユーザーの場所にアクセスするため。2つのキーを追加する必要があります
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のための問題を解決するのではなく、将来の互換性を保証しています。
これらのキーをiOS 8.4、iPad mini 2に追加しInfoPlist.strings
ました。のように、にキーを設定していません。NSLocationWhenInUseUsageDescription
Info.plist
InfoPlist.strings:
"NSLocationWhenInUseUsageDescription" = "I need GPS information....";
このスレッドにas in iOS 7
基づくと、InfoPlist.stringsでローカライズできます。私のテストでは、これらのキーをファイルで直接構成できますInfoPlist.strings
。
したがって、最初に行う必要があるのは、Info.plistファイルに次のキーの1つまたは両方を追加することです。
- NSLocationWhenInUseUsageDescription
- NSLocationAlwaysUsageDescription
これらのキーはどちらも、位置情報サービスが必要な理由を説明する文字列を取ります。「現在地を見つけるには位置情報が必要です」のような文字列を入力できます。これは、iOS 7のように、InfoPlist.stringsファイルでローカライズできます。
更新:
@IOS
の方がいいと思います。Info.plist
空の値のキーをに追加し、ローカライズされた文字列をに追加しますInfoPlist.strings
。