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]) { }