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 でこのプロジェクトを開始して以来、これらのエントリが欠落している可能性があると思います。Xcode 6 ではこれらのキーのデフォルト エントリが追加される可能性があると思いますが、確認していません。
これら 2 つの設定の詳細については、こちらを参照してください。
アップルのドキュメントによると:
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 にキーを追加し、位置情報管理者に開始を求める承認を要求します。新しい場所の承認には、Info.plist キーが 2 つあります。これらのキーのいずれかまたは両方が必要です。どちらのキーも存在しない場合、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
。
それでも承認を求めるウィンドウ ポップアップが表示されない場合は、View Controller のメソッドに行を追加しているかどうかを確認してvar locationManager = CLLocationManager()
くださいviewDidLoad
。そうすると、 を呼び出しlocationManager.requestWhenInUseAuthorization()
ても何も表示されません。これは、viewDidLoad の実行後に locationManager 変数の割り当てが解除される (クリアされる) ためです。
var locationManager = CLLocationManager()
解決策は、クラス メソッドの先頭にある行を見つけることです。
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 キーを設定します
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 でユーザーの場所にアクセスするには、追加する必要があります。
NSLocationAlwaysUsageDescription in the Info.plist
これにより、ユーザーは現在の場所を取得する許可を求められます。
複数の 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' {}
すべてのファイルに説明が追加されます。
Cocoa Keysの情報は、これらの更新のために常に手元に置いておいてください。リンクは次のとおりです。
楽しみ。
// ** 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]);
}
キー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 の問題を解決するだけでなく、将来の互換性を保証します。
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
。
したがって、最初に行う必要があるのは、次のキーの 1 つまたは両方を > Info.plist ファイルに追加することです。
- NSLocationWhenInUseUsageDescription
- NSLocationAlwaysUsageDescription
これらのキーはどちらも、位置情報サービスが必要な理由を説明する文字列を取ります。iOS 7のように、InfoPlist.strings ファイルでローカライズできる「現在地を調べるには場所が必要です」のような文字列を入力できます。
アップデート:
@IOS
の方法が良いと思います。キーをInfo.plist
空の値とともに追加し、ローカライズされた文字列を に追加しますInfoPlist.strings
。