Swiftでマップや位置情報を使う

Swift初心者のメモです。

iOS15で検証

マップ

基本となるインスタンス

import MapKit

let mapView = MKMapView()

ユーザーの現在地表示(青ポチのあれ)

mapView.showsUserLocation = true

ラッキングモード(青ポチが自動で移動するあれ)

mapView.userTrackingMode = MKUserTrackingMode.follow

// 方向を表示する場合
// mapView.userTrackingMode = MKUserTrackingMode.followWithHeading

MKUserTrackingMode.followまたは .followWithHeading を指定していると、初回表示で縮尺や中心を指定してなくても現在地が中心になる。

中心となる緯度経度の設定

let lat = CLLocationDegrees(<緯度>)
let lng = CLLocationDegrees(<経度>)
let loc: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat, lng)
mapView.setCenter(loc, animated: true)

縮尺の設定

var region: MKCoordinateRegion = mapView.region
region.span.latitudeDelta = 0.1
region.span.longitudeDelta = 0.1
region.center = loc // locは上記で定義
mapView.setRegion(region, animated: true)

setRegionを使う場合には region.center で中心地も指定できるので setCenter を使用する必要はない

タップした位置の緯度経度を取得する

let tapGesture = UITapGestureRecognizer(target: self, action: #selector(mapTapped(_:)))

mapView.addGestureRecognizer(tapGesture)

...

@objc func mapTapped(_ sender: UITapGestureRecognizer) {
  if sender.state == .ended {
    let tapPoint = sender.location(in: mapView)
    let coordinate = mapView.convert(tapPoint, toCoordinateFrom: mapView)
    print(coordinate.latitude)
    print(coordinate.longitude)
   }
}

アノテーションを加える(ピンみたいなマークのあれ)

let annotation = MKPointAnnotation()

annotation.coordinate = coordinate // CLLocationCoordinate2D

mapView.addAnnotation(annotation)

緯度経度から住所などの追加情報を取得

逆ジオコーディングと言われるやつ。

let cla = coordinate.latitude // CLLocationCoordinate2D
let clo = coordinate.longitude // CLLocationCoordinate2D

let location = CLLocation(latitude: cla, longitude: clo)

CLGeocoder().reverseGeocodeLocation(location, completionHandler: { placemarks, error in
  if error != nil {
    return
  }

  let placemark = placemarks.first
})

位置情報

基本となるインスタンス

import CoreLocation

let locationManager = CLLocationManager()

受け取りたい位置情報の正確さ

locationManager.desiredAccuracy = kCLLocationAccuracyBest // 最も精度が高い

iOSアプリの場合は kCLLocationAccuracyBest がデフォルト

バイスで位置情報が使用可能かどうか

CLLocationManager.locationServicesEnabled()

これはアプリレベルで位置情報の使用が許可されているかどうかではなく、デバイスレベルで使用可能かどうか。

設定の プライバシー > 位置情報サービス がオフになっているとfalseが返る。

使用許可のステータス

let status = locationManager.authorizationStatus

位置情報使用のリクエス

// バックグラウンドでも許可使用したい場合
locationManager.requestAlwaysAuthorization()

// アプリ使用中の許可を取りたい場合
locationManager.requestWhenInUseAuthorization()

どちらを実行しても「アプリ使用中の位置情報の取得の許可」のためのダイアログが表示される。

文言も NSLocationWhenInUseUsageDescription で指定したものが表示される。

このメソッドを実行した時点で CLLocationManager.locationServicesEnabled() がfalseだった場合、「位置情報サービスをオンにしてください」というアラートが自動で表示される。

requestAlwaysAuthorization()を実行した場合

初回ダイアログ

「Appの使用中は許可」を押すとコード上のステータスは authorizedAlways になる。

「一度だけ許可」を押すとコード上のステータスは authorizedWhenInUse になる。

「許可しない」だと denied になる。

authorizedWhenInUse の場合はバックグラウンドでは位置情報が更新できない。なのでバックグラウンドでも位置情報の更新を取得する必要があるアプリはアラートなので設定を authorizedAlways にするように誘導する必要がありそう。

This authorization allows you to use all location services and receive location events only when your app is in use. To continue using location services in the background, enable Continuous Background Location Updates and start the services while the app is in use.

denied の場合は位置情報が使用できないので、必須のアプリではアラートを出すなどしてアプリの機能を使えないことの通知が必要になりそう。

Appの使用中は許可を選択した場合

アプリの設定画面では「このAppの使用中のみ許可」になる。

コード状は authorizedAlways なので位置情報はバックグラウンドでも更新される。

しばらくして表示されるダイアログの 「”常に許可”に変更 」を押した時点でアプリ側の設定も変わる。

ここで「”使用中のみ許可”のままにする」にすると authorizedWhenInUse になる。

位置情報の許可ステータス変更によって実行されるdelegate

func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
  let status = locationManager.authorizationStatus
  switch status {

  }
}

位置情報の変更を検知させる

// 位置情報の更新を検知した場合、locationManagerを実行させる
locationManager.startUpdatingLocation()

...

// .startUpdatingLocation()が呼ばれている場合、位置情報の更新を受け取り実行される
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

}