// // LocationGeocoder.swift // suixinkan // import CoreLocation import Foundation /// 地址逆地理编码能力,供平台定位实现注入。 @MainActor protocol LocationAddressGeocoding: AnyObject { /// 将坐标解析为可读地址,失败时返回空字符串。 func reverseGeocode(latitude: Double, longitude: Double) async -> String } /// 平台逆地理编码封装;真机使用高德,模拟器使用 Core Location。 @MainActor final class LocationGeocoder: NSObject, LocationAddressGeocoding { nonisolated static let shared = LocationGeocoder() #if targetEnvironment(simulator) private let geocoder = CLGeocoder() #else private var searchAPI: AMapSearchAPI? private var continuation: CheckedContinuation? #endif nonisolated private override init() { super.init() } /// 将坐标解析为可读地址。 func reverseGeocode(latitude: Double, longitude: Double) async -> String { #if targetEnvironment(simulator) let location = CLLocation(latitude: latitude, longitude: longitude) guard let placemark = try? await geocoder.reverseGeocodeLocation(location).first else { return "" } if let name = placemark.name?.trimmingCharacters(in: .whitespacesAndNewlines), !name.isEmpty { return name } return [ placemark.administrativeArea, placemark.locality, placemark.subLocality, placemark.thoroughfare, placemark.subThoroughfare, ] .compactMap { $0?.trimmingCharacters(in: .whitespacesAndNewlines) } .filter { !$0.isEmpty } .joined() #else do { try AMapBootstrap.requireConfigured() } catch { return "" } return await withCheckedContinuation { continuation in self.continuation?.resume(returning: "") self.continuation = continuation guard let api = makeSearchAPI() else { continuation.resume(returning: "") return } let request = AMapReGeocodeSearchRequest() request.location = AMapGeoPoint.location(withLatitude: CGFloat(latitude), longitude: CGFloat(longitude)) request.requireExtension = true request.radius = 200 api.aMapReGoecodeSearch(request) } #endif } #if !targetEnvironment(simulator) func onReGeocodeSearchDone(_ request: AMapReGeocodeSearchRequest!, response: AMapReGeocodeSearchResponse!) { let address = response?.regeocode?.formattedAddress ?? "" continuation?.resume(returning: address) continuation = nil } func aMapSearchRequest(_ request: Any!, didFailWithError error: Error!) { continuation?.resume(returning: "") continuation = nil } private func makeSearchAPI() -> AMapSearchAPI? { if let searchAPI { return searchAPI } guard let api = AMapSearchAPI() else { return nil } api.delegate = self searchAPI = api return api } #endif } #if !targetEnvironment(simulator) extension LocationGeocoder: AMapSearchDelegate {} #endif