// // LocationManager.swift // Pods // // Created by Groot on 2025/5/15. // import Foundation import CoreLocation import Flutter class LocationManager: NSObject { static let shared = LocationManager() private var locationUpdateEventChannel: FlutterEventChannel? private var locationEventSink: FlutterEventSink? private let locationManager = CLLocationManager() #if DEBUG private let filterDistance: CLLocationDistance = 5 #else private let filterDistance: CLLocationDistance = 20 #endif private var lastLocation: CLLocation? private var lastUpdateTime: Date? var onLocationUpdate: ((CLLocation) -> Void)? private override init() { super.init() locationManager.delegate = self setup() } func initChannel(withMessenger messenger: FlutterBinaryMessenger) { locationUpdateEventChannel = FlutterEventChannel(name: MapKitConstans.locationUpdateEventChannelName, binaryMessenger: messenger) locationUpdateEventChannel?.setStreamHandler(self) } func start(withMessenger messenger: FlutterBinaryMessenger) -> Bool { // permission detect switch CLLocationManager.authorizationStatus() { case .authorizedWhenInUse, .authorizedAlways: locationManager.startUpdatingLocation() //setupMessenger(messenger: messenger) return true case .notDetermined: return false default: print("LocationManager: authorizationStatus: \(CLLocationManager.authorizationStatus())") return false } } func stop() { locationManager.stopUpdatingLocation() } // func setupMessenger(messenger: FlutterBinaryMessenger) { // guard locationUpdateEventChannel == nil && locationEventSink == nil else { return } // locationUpdateEventChannel = FlutterEventChannel(name: MapKitConstans.locationUpdateEventChannelName, binaryMessenger: messenger) // locationUpdateEventChannel?.setStreamHandler(self) // } func setup() { locationManager.allowsBackgroundLocationUpdates = true locationManager.pausesLocationUpdatesAutomatically = false locationManager.desiredAccuracy = kCLLocationAccuracyBest // locationManager.distanceFilter = filterDistance locationManager.activityType = .automotiveNavigation locationManager.showsBackgroundLocationIndicator = false } static func getAddress(location: CLLocation) async -> String? { let geocoder = CLGeocoder() return await withCheckedContinuation { continuation in geocoder.reverseGeocodeLocation(location) { (placemarks, error) in if let error = error { print("反向地理编码失败: \(error.localizedDescription)") continuation.resume(returning: nil) return } if let placemark = placemarks?.first { // 获取完整地址 let address = [ placemark.country, placemark.administrativeArea, placemark.locality, placemark.subLocality, placemark.thoroughfare, placemark.subThoroughfare, placemark.name ].compactMap { $0 }.joined(separator: "") continuation.resume(returning: address) } else { continuation.resume(returning: nil) } } } } } extension LocationManager: CLLocationManagerDelegate { func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { guard let location = locations.last, isLocationCanUpdate(location: location) else { return } onLocationUpdate?(location) if let eventSink = locationEventSink { Task { // 转换GPS坐标系到中国坐标系 let transformedCoordinate = location.coordinate.wgc84ToGCJ02 let atLocation = ATMapLocation.fromLocation(location: location) atLocation.longitude = transformedCoordinate.longitude atLocation.latitude = transformedCoordinate.latitude // 获取地址 atLocation.address = await LocationManager.getAddress(location: location) let jsonMessage = atLocation.toJson() print(jsonMessage) await MainActor.run { eventSink(jsonMessage) } } } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { print("LocationManager: didFailWithError: \(error)") } func isLocationCanUpdate(location: CLLocation) -> Bool { if let lastLocation = lastLocation { let distance = location.distance(from: lastLocation) let timeInterval = location.timestamp.timeIntervalSince(lastUpdateTime ?? Date()) if timeInterval < 5.0 { return false } } lastLocation = location lastUpdateTime = location.timestamp return true } } extension LocationManager: FlutterStreamHandler { func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? { locationEventSink = events return nil } func onCancel(withArguments arguments: Any?) -> FlutterError? { locationEventSink = nil return nil } }