【Swift】CoreLocationを使用してバックグラウンドモードで位置情報を取得する方法【Objective-C】【iOS13】

2020年8月27日

CoreLocationにあるCLLocationManagerクラスを使用して位置情報を取得する方法をご紹介します。

位置情報の取得には、フォアグラウンド時、バックグラウンド時の他にも、アプリ使用中のみ、常に許可、などのステータスがあります。

今回は、フォアグランド、バックグラウンド両方で常に位置情報が取れる場合のサンプルプログラムを紹介いたします。

ご利用の用途に合わせてカスタマイズしてみてください。

バックグラウンドモードで位置情報を取得する方法

バックグラウンドモードで取得できるように設定する

1.Background ModesのLocation updatesにチェックを入れる

TARGET > Signing & Capabilities を開きます。

次に +Capability > Background Modes を選択します。

最後に Background Modes > Location updates にチェックを入れます。

2.plistに認証ダイアログででる文言を設定する

「常に許可する」や「アプリ使用中のみ許可する」など使用する用途によって必要な項目が違いますが、とりあえず4つとも追加しておくといいでしょう。

・Privacy - Location Always and When In Use Usage Description
・Privacy - Location Always Usage Description
・Privacy - Location Usage Description
・Privacy - Location When In Use Usage Description

プログラム

さて、設定が終わったら次はプログラムです。
サンプルプログラムを用意しましたので必要に応じて追加してください。

Swift5

import UIKit

import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {
    
    var locationManager : CLLocationManager!

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        
        locationManager = CLLocationManager.init()
        locationManager.allowsBackgroundLocationUpdates = true; // バックグランドモードで使用する場合YESにする必要がある
        locationManager.desiredAccuracy = kCLLocationAccuracyBest; // 位置情報取得の精度
        locationManager.distanceFilter = 1; // 位置情報取得する間隔、1m単位とする
        locationManager.delegate = self as? CLLocationManagerDelegate;
        
        // 位置情報の認証チェック
        let status = CLLocationManager.authorizationStatus()
        if (status == .notDetermined) {
            print("許可、不許可を選択してない");
            // 常に許可するように求める
            locationManager.requestAlwaysAuthorization();
        }
        else if (status == .restricted) {
            print("機能制限している");
        }
        else if (status == .denied) {
            print("許可していない");
        }
        else if (status == .authorizedWhenInUse) {
            print("このアプリ使用中のみ許可している");
            locationManager.startUpdatingLocation();
        }
        else if (status == .authorizedAlways) {
            print("常に許可している");
            locationManager.startUpdatingLocation();
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //**************************************************
    // CLLocationManagerDelegate
    //**************************************************
    
    // 位置情報が取得されると呼ばれる
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        // 最新の位置情報を取得 locationsに配列で入っている位置情報の最後が最新となる
        let location : CLLocation = locations.last!;
    }
    
    // 位置情報の取得に失敗すると呼ばれる
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {

    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if (status == .restricted) {
            print("機能制限している");
        }
        else if (status == .denied) {
            print("許可していない");
        }
        else if (status == .authorizedWhenInUse) {
            print("このアプリ使用中のみ許可している");
            locationManager.startUpdatingLocation();
        }
        else if (status == .authorizedAlways) {
            print("常に許可している");
            locationManager.startUpdatingLocation();
        }
    }
}

Objective-C

#import "ViewController.h"

#import <CoreLocation/CoreLocation.h>

@interface ViewController () <CLLocationManagerDelegate> {
    CLLocationManager *locationManager;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    locationManager = [[CLLocationManager alloc] init];
    locationManager.allowsBackgroundLocationUpdates = YES; // バックグランドモードで使用する場合YESにする必要がある
    locationManager.desiredAccuracy = kCLLocationAccuracyBest; // 位置情報取得の精度
    locationManager.distanceFilter = 1; // 位置情報取得する間隔、1m単位とする
    locationManager.delegate = self;
    
    // 位置情報の認証チェック
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
        NSLog(@"許可、不許可を選択してない");
        [locationManager requestAlwaysAuthorization];
    }
    else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) {
        NSLog(@"機能制限している");
    }
    else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
        NSLog(@"許可していない");
    }
    else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) {
        NSLog(@"このアプリ使用中のみ許可している");
        [locationManager startUpdatingLocation];
    }
    else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways) {
        NSLog(@"常に許可している");
        [locationManager startUpdatingLocation];
    }
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

//**************************************************
// CLLocationManagerDelegate
//**************************************************

// 位置情報が取得されると呼ばれる
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations {
    // 最新の位置情報を取得 locationsに配列で入っている位置情報の最後が最新となる
    CLLocation *location = [locations lastObject];
}
// 位置情報の取得に失敗すると呼ばれる
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {

}
// 位置情報の認証のダイアログで選んだステータスが呼ばれる
- (void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status {
    // 位置情報の認証チェック
    if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusRestricted) {
        NSLog(@"機能制限している");
    }
    else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusDenied) {
        NSLog(@"許可していない");
    }
    else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse) {
        NSLog(@"このアプリ使用中のみ許可している");
        [locationManager startUpdatingLocation];
    }
    else if ([CLLocationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedAlways) {
        NSLog(@"常に許可している");
        [locationManager startUpdatingLocation];
    }
}

@end

バックグラウンドモードで位置情報が取得できない場合に確認すること

位置情報の使用許可を 使用中は許可 → 常に許可 に変更する

アプリインストール + 起動時に位置情報の使用許可の確認がでます。

Appに使用中は許可 に設定しましょう。

これを設定しないとフォアグラウンドでも位置情報を取得できません。

さらにバックグラウンドで位置情報を取得するには

アプリがバックグランドモードで位置情報を取得しようとした時に、さらに位置情報の使用許可の確認がでます。

"常に許可"に変更 に設定しましょう。

この設定をしないと、バックグラウンドモードで位置情報を取得することはできないので注意してください。

iOSの設定からアプリ個別の位置情報許可設定を変更する

上記のような位置情報許可のアラートが出ない場合はiOSの設定からアプリ個別の位置情報許可を変更しましょう。

設定アプリ > プライバシー > 位置情報サービス > 該当アプリ > 常に に変更します。

以上でバックグラウンドモードでもしっかりと位置情報が取得できると思います。