1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【SwiftUI】位置情報を記録して通った道をマップに表示するアプリを作ってみよう

Last updated at Posted at 2024-09-01

SwiftUIを使って、ユーザーの位置情報を記録し、通った道をマップに青い線で表示するアプリを作る方法を解説します。iOS 17の新しいMap APIを活用します。

0902-3__4.gif

1. プロジェクトのセットアップ

まず、Xcodeで新しいSwiftUIプロジェクトを作成しましょう。プロジェクト名は「TrackMyRoute」など、好きな名前でOKです。

1.1 位置情報の権限を設定する

位置情報を使用するには、Info.plistに位置情報の使用許可をリクエストするキーを追加する必要があります。

Info.plist に以下のキーを追加してください。

<key>NSLocationWhenInUseUsageDescription</key>
<string>アプリが使用中に位置情報を取得します。</string>

:bulb: Info.plistがない場合は、GUIからも追加できます。
plist位置情報 (2).gif

これで、アプリが位置情報を取得するための許可をユーザーにリクエストできるようになります。

2. 位置情報を管理する LocationManager の作成

次に、位置情報を管理し、通った道を記録するための LocationManager クラスを作成します。

2.1 LocationManager.swift の作成

プロジェクト内のContentView.swiftなどと同じ場所に、新しい Swift ファイルを作成し、LocationManager.swift と名前を付けます。以下のコードを追加します。

import Foundation
import CoreLocation

class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    private var locationManager = CLLocationManager()
    
    @Published var location: CLLocation? = nil
    @Published var locationError: String? = nil
    @Published var authorizationStatus: CLAuthorizationStatus?
    @Published var locations: [CLLocationCoordinate2D] = []  // 位置情報の履歴を保持
    
    override init() {
        super.init()
        locationManager.delegate = self
        
        // 権限のリクエスト
        locationManager.requestWhenInUseAuthorization()
        
        // 現在の権限状態を初期化
        let status = locationManager.authorizationStatus
        self.authorizationStatus = status
        print("Location authorization status: \(status)")
        
        // 位置情報の取得を開始
        locationManager.startUpdatingLocation()
    }
    
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        DispatchQueue.main.async {
            self.authorizationStatus = status
            print("Authorization status changed: \(status.rawValue)")
            
            if status == .authorizedWhenInUse || status == .authorizedAlways {
                self.locationManager.startUpdatingLocation()
            } else {
                self.locationError = "位置情報の権限が許可されていません。設定を確認してください。"
            }
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if let lastLocation = locations.last {
            DispatchQueue.main.async {
                self.location = lastLocation
                self.locationError = nil  // エラーメッセージをクリア
                self.locations.append(lastLocation.coordinate)  // 位置情報を記録
            }
            print("Updated location: \(lastLocation.coordinate.latitude), \(lastLocation.coordinate.longitude)")
        } else {
            print("No location data available")
        }
    }
    
    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        DispatchQueue.main.async {
            self.locationError = error.localizedDescription
        }
        
        if let clError = error as? CLError {
            switch clError.code {
            case .denied:
                print("Location access denied by the user")
                self.locationError = "位置情報へのアクセスが拒否されました。設定を確認してください。"
            case .locationUnknown:
                print("Location is currently unknown, but it may be available later")
                self.locationError = "現在の位置情報は取得できませんが、後ほど利用可能になるかもしれません。"
            default:
                print("Location Manager failed with error: \(error.localizedDescription)")
                self.locationError = "位置情報の取得に失敗しました。エラー: \(error.localizedDescription)"
            }
        } else {
            print("Failed to get location: \(error.localizedDescription)")
            self.locationError = "位置情報の取得に失敗しました。エラー: \(error.localizedDescription)"
        }
    }
}

このクラスは、ユーザーの位置情報を取得し、エラーをハンドリングしながら位置情報を記録します。

3. 位置情報を利用してマップを表示する

次に、位置情報を使用して地図上に通った道を描画する ContentView を作成します。

3.1 ContentView.swift の実装

ContentView.swift を以下のように修正します。

import SwiftUI
import CoreLocation
import MapKit

struct ContentView: View {
    
    @StateObject private var locationManager = LocationManager()
    @State var position: MapCameraPosition = .automatic
    
    var body: some View {
        VStack {
            if !locationManager.locations.isEmpty {
                Map(position: $position) {
                    // 通った道を描画
                    MapPolyline(coordinates: locationManager.locations)
                        .stroke(.blue, lineWidth: 5)
                }
                .mapControls {
                    MapUserLocationButton()
                }
                .onAppear {
                    if let firstLocation = locationManager.locations.first {
                        position = .region(MKCoordinateRegion(center: firstLocation, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)))
                        print("Map region set to first location: \(firstLocation.latitude), \(firstLocation.longitude)")
                    }
                }
            } else if let error = locationManager.locationError {
                Text("位置情報の取得に失敗しました: \(error)")
                    .foregroundColor(.red)
                    .onAppear {
                        print("Error occurred: \(error)")
                    }
            } else {
                Text("位置情報を取得中...")
                    .onAppear {
                        print("Waiting for location data...")
                    }
            }
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

このコードは、ユーザーの現在位置に基づいてマップを表示し、通った道を青色の線で描画します。

4. 最後に

これで、ユーザーの位置情報を記録し、通った道をマップに表示するアプリが完成しました。今回紹介した手法は、ランニングやサイクリングのアプリケーションでの利用にも応用可能です。

もしこの記事が役に立ったら、ぜひ「いいね」や「ストック」をお願いします。また、質問やフィードバックがあれば、コメント欄でお知らせください!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?