// // LocationService.swift // ylgamehall // // 高德 AMapLocationManager 异步包装:一次性 / 持续两种模式。 // 契约 §3.2 [6] getlocationinfo 9 字段;msext gameController.m:2491-2557 等价。 // // ⚠️ canImport(AMapLocationKit) 守卫:SDK 未链接时 LocationService 永远抛 // LocationError.sdkNotLinked,handler 兜底退化为 stub 行为。 // import Foundation import CoreLocation #if canImport(AMapLocationKit) import AMapLocationKit #endif #if canImport(AMapFoundationKit) import AMapFoundationKit #endif /// 9 字段定位结果。字段名严格 1:1 H5 端契约(contract §3.2 表 [6]): /// - latitude / longitude **是 string** (`String(format: "%f", ...)`) /// - province **小写 p**(与 sharelogin.Province 大写不同) public struct LocationPayload: Sendable { public let address: String public let city: String public let cityCode: String public let country: String public let district: String public let latitude: String public let longitude: String public let province: String public let street: String } public enum LocationError: Error, Sendable { case sdkNotLinked case authorizationDenied case timeout case underlying(any Error) } @MainActor public final class LocationService { public static let shared = LocationService() public init() {} #if canImport(AMapLocationKit) private let manager: AMapLocationManager = { let m = AMapLocationManager() m.desiredAccuracy = kCLLocationAccuracyHundredMeters m.locationTimeout = 6 m.reGeocodeTimeout = 3 m.locatingWithReGeocode = true return m }() #endif /// 一次性定位 + 逆地理(msext locAction + completionBlock 等价) public func requestOnce() async throws -> LocationPayload { #if canImport(AMapLocationKit) return try await withCheckedThrowingContinuation { (cont: CheckedContinuation) in manager.requestLocation(withReGeocode: true) { loc, regeo, err in if let err = err as NSError? { // msext 行为:权限相关错误归一到 12 errorCode(handler 转字段) if err.code == AMapLocationErrorCode.locateFailed.rawValue { cont.resume(throwing: LocationError.authorizationDenied) } else { cont.resume(throwing: LocationError.underlying(err)) } return } guard let loc, let regeo else { cont.resume(throwing: LocationError.timeout) return } cont.resume(returning: LocationPayload( address: regeo.formattedAddress ?? "", city: regeo.city ?? "", cityCode: regeo.citycode ?? "", country: regeo.country ?? "", district: regeo.district ?? "", latitude: String(format: "%f", loc.coordinate.latitude), longitude: String(format: "%f", loc.coordinate.longitude), province: regeo.province ?? "", street: regeo.street ?? "" )) } } #else throw LocationError.sdkNotLinked #endif } /// 停止:msext gameController.m:2473-2478 cleanUpAction 等价 public func stop() { #if canImport(AMapLocationKit) manager.stopUpdatingLocation() manager.delegate = nil #endif } }