iOS MapKit 地圖與定位整合教學

MapKit 讓我們能輕鬆在 App 中嵌入 Apple Maps。在 SwiftUI 中,新的 Map API (iOS 17+) 變得非常直觀。

顯示地圖與控制視角

使用 MapCameraPosition 來控制地圖的顯示區域。

import MapKit

struct ContentView: View {
    // 預設位置:台北 101
    @State private var position: MapCameraPosition = .region(
        MKCoordinateRegion(
            center: CLLocationCoordinate2D(latitude: 25.0339, longitude: 121.5644),
            span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
        )
    )

    var body: some View {
        Map(position: $position) {
            // 加入標記
            Marker("台北 101", coordinate: CLLocationCoordinate2D(latitude: 25.0339, longitude: 121.5644))
        }
        .mapStyle(.hybrid(elevation: .realistic)) // 3D 混合衛星地圖
        .mapControls {
            MapUserLocationButton() // 顯示「回到目前位置」按鈕
            MapCompass() // 指南針
            MapScaleView() // 比例尺
        }
    }
}

獲取使用者位置 (Core Location)

要獲取定位,需要使用 CLLocationManager

步驟 1: 新增 Info.plist 權限

請在 Info.plist 新增以下 Key:

  • Privacy - Location When In Use Usage Description: 告訴使用者為什麼你需要定位。

步驟 2: 建立 Manager

class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    let manager = CLLocationManager()
    @Published var location: CLLocation?
    @Published var authorizationStatus: CLAuthorizationStatus = .notDetermined

    override init() {
        super.init()
        manager.delegate = self
        manager.desiredAccuracy = kCLLocationAccuracyBest
    }
    
    // 請求權限
    func requestPermission() {
        manager.requestWhenInUseAuthorization()
    }
    
    // Delegate: 權限狀態改變
    func locationManagerDidChangeAuthorization(_ manager: CLLocationManager) {
        authorizationStatus = manager.authorizationStatus
        if authorizationStatus == .authorizedWhenInUse || authorizationStatus == .authorizedAlways {
            manager.startUpdatingLocation()
        }
    }

    // Delegate: 位置更新
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        location = locations.first
    }
}

步驟 3: 在 Map 中顯示

Map {
    UserAnnotation() // 顯示藍色小圓點
}

繪製路徑 (Polyline)

如果要在地圖上畫出跑步路徑或導航路線,可以使用 MapPolyline

let locations = [
    CLLocationCoordinate2D(latitude: 25.0339, longitude: 121.5644), // 起點
    CLLocationCoordinate2D(latitude: 25.0380, longitude: 121.5644), // 中點
    CLLocationCoordinate2D(latitude: 25.0400, longitude: 121.5700)  // 終點
]

Map {
    MapPolyline(coordinates: locations)
        .stroke(.blue, lineWidth: 5)
}

搜尋地點 (MKLocalSearch)

MapKit 內建了搜尋興趣點 (POI) 的功能。

func searchPlaces(query: String) async -> [MKMapItem] {
    let request = MKLocalSearch.Request()
    request.naturalLanguageQuery = query
    request.resultTypes = .pointOfInterest
    
    guard let response = try? await MKLocalSearch(request: request).start() else {
        return []
    }
    return response.mapItems
}

地圖與定位是 LBS (Location Based Service) 應用的核心,結合兩者可以開發出導航、周邊搜尋等強大功能。