iOS アプリで現在地情報を取得する方法 (Swift)
ここでは、iOS アプリで現在地情報を取得する方法をご説明します。
今回は、以下のように Get Current Location というボタンをタップした時に、ラベルに現在地の情報を表示するだけのシンプルな iOS アプリを作ります。
現在地を取得する iOS アプリの準備をする
まずはテスト用にボタンをタップして、現在地を取得して表示するための、簡単な iOS アプリを作ります。
Xcode で [iOS] の [App] の新規プロジェクトを作成します。
デザインや場所などは適当で良いので、Main ストーリーボードの View Controller に、上から順番にラベル二つとボタンをひとつ追加します。
一つ目ラベルは Text を Current Location に変更しました。
二つ目のラベルに現在地情報を表示するので、サイズを大きめにして Lines を 10 にし、Background に薄いグレーの色をつけました。
ボタンは Text を Get Current Location に変更しました。
ラベル・ボタンの追加の方法や、アウトレット・アクションの作り方がわからない方は「基本的な iOS アプリの作り方」をご覧ください。
アウトレットと、ボタンのアクションを生成します。
二つ目のラベルから locationInfoLabel という名前でアウトレットを生成します。
ボタンから、getCurrentLocationTapped という名前で TouchUpInside のアクションを作っておきます。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var locationInfoLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func getCurrentLocationTapped(_ sender: Any) {
}
}
以上で、現在地を取得する iOS アプリの準備は終わりです。
iOS アプリで現在地情報を取得する方法
それでは、Swift で 現在地情報を取得するコードを書いていきましょう。
位置情報を取得するには、CoreLocation というフレームワークを使うので、CoreLocation をインポートします。
具体的には CLLocationManager クラスを使って、現在地を取得します。
そして、ViewController で CLLocationManager からのイベント受け取るために、CLLocationManagerDelegate をコンフォームしておきます。
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
@IBOutlet weak var locationInfoLabel: UILabel!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
}
@IBAction func getCurrentLocationTapped(_ sender: Any) {
}
}
CLLocationManager から受け取ることができるイベントはいろいろありますが、今回は以下の二つを受け取るようにします。
- locationManager(_:didUpdateLocations:) - 新しいロケーションデータが取得された時に実行されます。
- locationManager(_:didFailWithError:) - ロケーションデータが取得できなかった時に実行されます。
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
}
続いて viewDidLoad() を次のように変更します。
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
}
desiredAccuracy は精度の指標で、今回は精度の高い kCLLocationAccuracyBest にしましたが、精度を落とすとより早く位置情報を取得できる場合があるので、必要最低限のものを選ぶと良いかと思います。
今回はアプリを使用している時のみ位置情報が取得できれば良いので、requestWhenInUseAuthorization() メソッドで、アプリの使用中のみロケーションサービスを使う許可をリクエストしています。
常にロケーションサービスを使用したい時は requestAlwaysAuthorization() メソッドを実行してください。
今回のアプリではボタンがタップされた時 getCurrentLocationTapped() で位置情報取得のリクエストをして、locationManager(_:didUpdateLocations:) で位置情報を取得し、リバースジオコーディングしてラベルに表示します。
コードは次の通りです。
import UIKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
@IBOutlet weak var locationInfoLabel: UILabel!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
}
@IBAction func getCurrentLocationTapped(_ sender: Any) {
locationManager.requestLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let loc = locations.last else { return }
CLGeocoder().reverseGeocodeLocation(loc, completionHandler: {(placemarks, error) in
if let error = error {
print("reverseGeocodeLocation Failed: \(error.localizedDescription)")
return
}
if let placemark = placemarks?[0] {
var locInfo = ""
locInfo = locInfo + "Latitude: \(loc.coordinate.latitude)\n"
locInfo = locInfo + "Longitude: \(loc.coordinate.longitude)\n\n"
locInfo = locInfo + "Country: \(placemark.country ?? "")\n"
locInfo = locInfo + "State/Province: \(placemark.administrativeArea ?? "")\n"
locInfo = locInfo + "City: \(placemark.locality ?? "")\n"
locInfo = locInfo + "PostalCode: \(placemark.postalCode ?? "")\n"
locInfo = locInfo + "Name: \(placemark.name ?? "")"
self.locationInfoLabel.text = locInfo
}
})
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("error: \(error.localizedDescription)")
}
}
18 行目の locationManager.requestLocation() で位置情報取得のリクエストをしています。
今回はボタンをタップした時に一度だけ位置情報を取得したいので、requestLocation() を使っていますが、続けて位置情報を取得したい時は startUpdatingLocation() でスタート、stopUpdatingLocation() でストップすることもできます。
22 行目で位置情報を取得しています。locations 配列には、一番最新のロケーションは最後に入っているので last で最新のロケーションを取得しています。
24 行目で CLGeocoder().reverseGeocodeLocation() メソッドを使って、取得した CLLocation データから国や市などの情報を取得しています。
reverseGeocodeLocation の結果がエラーでなければ、33 ~ 41 行目で位置情報の文字列を生成し、43 行目で locationInfoLabel に表示しています。
49 行目では locationManager(_:didFailWithError:) を受け取った時にエラーの内容を print しています。
iOS アプリで現在地情報を取得するコードの説明は以上です。
info.plist にロケーションサービス使用許可のための行を追加する
先ほどのコードをそのまま実行すると、次のようなメッセージが output に表示され、位置情報は取得できません。
This app has attempted to access privacy-sensitive data without a usage description. The app's Info.plist must contain an “NSLocationWhenInUseUsageDescription” key with a string value explaining to the user how the app uses this data
info.plist に NSLocationWhenInUseUsageDescription (Privacy - Location When In Use Usage Description) の行を追加する必要があります。
info.plist ファイルを開いて、欄外で右クリックをして [Add Row] を選択します。
Key に NSLocationWhenInUseUsageDescription を入力して、Value にユーザに位置情報の使用許可を求める際に表示される、位置情報の使用用途の説明を入力します。
アプリの使用中だけではなく、常に位置情報を取得したい時は代わりに NSLocationAlwaysAndWhenInUseUsageDescription を追加してください。
シミュレーターで現在地情報を取得するアプリのテストをする
作った iOS アプリをシミュレーターにインストールしてテストします。
アプリが起動すると、次のようにロケーション情報を使う許可を求める画面が出てくるので「Allow While Using App(App の使用中は許可)」をタップします。
最初の画面が表示されるので、「Get Current Location」をタップすると、現在地情報が取得され、ラベルに表示されます。
シミュレーターの Location は Apple になっていますが、Custom Location に変更して、緯度軽度を設定してテストすることも可能です。
以上、iOS アプリで現在地情報を取得する方法をご説明しました。