|
|
|
@ -9,349 +9,368 @@ public extension Notification.Name { |
|
|
|
|
|
|
|
public class LocationService: NSObject { |
|
|
|
private static let TAG = "LocationService" |
|
|
|
private static let CACHE_PREFS_NAME = "location_cache" |
|
|
|
private static let PERMISSION_REQUEST_CODE = 1001 |
|
|
|
|
|
|
|
public static let shared = LocationService() |
|
|
|
|
|
|
|
private var locationManager: CLLocationManager? |
|
|
|
private var initialized = false |
|
|
|
private var permissionRetryTimer: Timer? |
|
|
|
|
|
|
|
// 存储当前的定位请求回调(Flutter用) |
|
|
|
private var cachedLocationData: LocationData? |
|
|
|
private var currentLocationCallback: ((Result<[String: Any], Error>) -> Void)? |
|
|
|
// 存储权限请求回调(Flutter用) |
|
|
|
private var permissionRequestCallback: ((Result<[String: Bool], Error>) -> Void)? |
|
|
|
|
|
|
|
// 存储服务间调用的回调 |
|
|
|
private var serviceCallbacks: [LocationCallback] = [] |
|
|
|
// 缓存有效期(5分钟) |
|
|
|
private let cacheValidityDuration: TimeInterval = 5 * 60 |
|
|
|
|
|
|
|
// 缓存的位置数据 |
|
|
|
private var cachedLocationData: LocationData? |
|
|
|
// 权限状态缓存 |
|
|
|
private var authorizationStatus: CLAuthorizationStatus = .notDetermined |
|
|
|
private var isLocationServicesEnabled: Bool = false |
|
|
|
|
|
|
|
private override init() { |
|
|
|
super.init() |
|
|
|
} |
|
|
|
|
|
|
|
/// 检查应用是否在前台运行 |
|
|
|
public func isAppInForeground() -> Bool { |
|
|
|
return UIApplication.shared.applicationState == .active |
|
|
|
} |
|
|
|
|
|
|
|
/// 初始化定位服务 |
|
|
|
public func initialize() { |
|
|
|
if initialized { return } |
|
|
|
|
|
|
|
if !checkPermissions() { |
|
|
|
print("\(LocationService.TAG): 没有定位权限,等待用户授权中...") |
|
|
|
startPermissionMonitor() |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
setupLocationManager() |
|
|
|
initialized = true |
|
|
|
print("\(LocationService.TAG): 定位服务初始化完成") |
|
|
|
} |
|
|
|
|
|
|
|
private func setupLocationManager() { |
|
|
|
locationManager = CLLocationManager() |
|
|
|
locationManager?.delegate = self |
|
|
|
locationManager?.desiredAccuracy = kCLLocationAccuracyBest |
|
|
|
locationManager?.distanceFilter = 10 |
|
|
|
} |
|
|
|
|
|
|
|
private func startPermissionMonitor() { |
|
|
|
permissionRetryTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: true) { [weak self] _ in |
|
|
|
guard let self = self else { return } |
|
|
|
let hasPermission = self.checkPermissions() |
|
|
|
if hasPermission && !self.initialized { |
|
|
|
print("\(LocationService.TAG): 权限已授予,重新初始化定位服务") |
|
|
|
self.initialize() |
|
|
|
self.stopPermissionMonitor() |
|
|
|
} |
|
|
|
DispatchQueue.main.async { [weak self] in |
|
|
|
self?.locationManager = CLLocationManager() |
|
|
|
self?.locationManager?.delegate = self |
|
|
|
self?.locationManager?.desiredAccuracy = kCLLocationAccuracyBest |
|
|
|
self?.locationManager?.distanceFilter = 10 |
|
|
|
|
|
|
|
// 初始化时获取当前状态 |
|
|
|
self?.authorizationStatus = CLLocationManager.authorizationStatus() |
|
|
|
self?.isLocationServicesEnabled = CLLocationManager.locationServicesEnabled() |
|
|
|
|
|
|
|
print("[LocationService] LocationManager 初始化完成") |
|
|
|
print("[LocationService] 初始权限状态: \(self?.authorizationStatus.rawValue ?? -1)") |
|
|
|
print("[LocationService] 位置服务启用: \(self?.isLocationServicesEnabled ?? false)") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private func stopPermissionMonitor() { |
|
|
|
permissionRetryTimer?.invalidate() |
|
|
|
permissionRetryTimer = nil |
|
|
|
} |
|
|
|
|
|
|
|
/// 检查定位权限 |
|
|
|
private func checkPermissions() -> Bool { |
|
|
|
return hasForegroundLocationPermission() |
|
|
|
} |
|
|
|
|
|
|
|
private func hasForegroundLocationPermission() -> Bool { |
|
|
|
let status = CLLocationManager.authorizationStatus() |
|
|
|
return status == .authorizedWhenInUse || status == .authorizedAlways |
|
|
|
} |
|
|
|
|
|
|
|
private func hasBackgroundLocationPermission() -> Bool { |
|
|
|
return CLLocationManager.authorizationStatus() == .authorizedAlways |
|
|
|
} |
|
|
|
|
|
|
|
/// 检查定位权限状态(Flutter用) |
|
|
|
public func checkLocationPermission(completion: @escaping (Result<[String: Bool], Error>) -> Void) { |
|
|
|
let hasPermission = checkPermissions() |
|
|
|
let result: [String: Bool] = [ |
|
|
|
"hasPermission": hasPermission, |
|
|
|
"hasForegroundPermission": hasForegroundLocationPermission(), |
|
|
|
"hasBackgroundPermission": hasBackgroundLocationPermission() |
|
|
|
] |
|
|
|
completion(.success(result)) |
|
|
|
} |
|
|
|
|
|
|
|
/// 请求定位权限(Flutter用) |
|
|
|
public func requestLocationPermission(completion: @escaping (Result<[String: Bool], Error>) -> Void) { |
|
|
|
if checkPermissions() { |
|
|
|
completion(.success(["granted": true])) |
|
|
|
/// 获取当前位置 - 主要接口 |
|
|
|
public func getCurrentLocation(completion: @escaping (Result<[String: Any], Error>) -> Void) { |
|
|
|
print("[LocationService] 开始获取当前位置") |
|
|
|
|
|
|
|
// 1. 检查缓存数据是否存在且有效 |
|
|
|
if let cachedData = getCachedLocationIfValid() { |
|
|
|
print("[LocationService] 返回缓存位置数据") |
|
|
|
let locationInfo = formatLocationData(cachedData) |
|
|
|
completion(.success(locationInfo)) |
|
|
|
|
|
|
|
// 异步更新缓存 |
|
|
|
print("[LocationService] 异步更新位置缓存") |
|
|
|
asyncUpdateLocation() |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
permissionRequestCallback = completion |
|
|
|
locationManager?.requestWhenInUseAuthorization() |
|
|
|
// 2. 缓存不存在或已过期,检查权限并同步获取位置 |
|
|
|
print("[LocationService] 缓存无效,开始同步获取位置") |
|
|
|
syncGetLocation(completion: completion) |
|
|
|
} |
|
|
|
|
|
|
|
/// 按需获取当前位置(Flutter用) |
|
|
|
public func getCurrentLocation(completion: @escaping (Result<[String: Any], Error>) -> Void) { |
|
|
|
if !checkPermissions() { |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -2, userInfo: [NSLocalizedDescriptionKey: "需要定位权限"]))) |
|
|
|
return |
|
|
|
/// 检查缓存是否有效 |
|
|
|
private func getCachedLocationIfValid() -> LocationData? { |
|
|
|
guard let cached = cachedLocationData else { |
|
|
|
print("[LocationService] 无缓存数据") |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
if !initialized { |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -3, userInfo: [NSLocalizedDescriptionKey: "定位服务未初始化"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
let currentTime = Date().timeIntervalSince1970 * 1000 |
|
|
|
let cacheAge = currentTime - cached.timestamp |
|
|
|
|
|
|
|
if currentLocationCallback != nil { |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -4, userInfo: [NSLocalizedDescriptionKey: "正在定位中,请稍后再试"]))) |
|
|
|
return |
|
|
|
if cacheAge < cacheValidityDuration * 1000 { |
|
|
|
print("[LocationService] 缓存有效,年龄: \(cacheAge/1000)秒") |
|
|
|
return cached |
|
|
|
} else { |
|
|
|
print("[LocationService] 缓存已过期,年龄: \(cacheAge/1000)秒") |
|
|
|
return nil |
|
|
|
} |
|
|
|
|
|
|
|
// 保存回调,开始定位 |
|
|
|
currentLocationCallback = completion |
|
|
|
locationManager?.requestLocation() |
|
|
|
} |
|
|
|
|
|
|
|
// MARK: - 供其他iOS服务使用的接口 |
|
|
|
|
|
|
|
/// 检查是否有定位权限(供其他服务使用) |
|
|
|
public func hasLocationPermission() -> Bool { |
|
|
|
return checkPermissions() |
|
|
|
/// 异步更新位置缓存 |
|
|
|
private func asyncUpdateLocation() { |
|
|
|
// 检查权限 |
|
|
|
guard checkLocationPermission() else { |
|
|
|
print("[LocationService] 异步更新失败:无位置权限") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 异步请求位置更新 |
|
|
|
DispatchQueue.global(qos: .background).async { [weak self] in |
|
|
|
self?.requestLocationUpdate { result in |
|
|
|
switch result { |
|
|
|
case .success(let locationData): |
|
|
|
print("[LocationService] 异步更新位置缓存成功") |
|
|
|
self?.cachedLocationData = locationData |
|
|
|
case .failure(let error): |
|
|
|
print("[LocationService] 异步更新位置缓存失败: \(error.localizedDescription)") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 异步获取当前位置(供其他iOS服务使用) |
|
|
|
public func getCurrentLocation() async throws -> LocationData { |
|
|
|
return try await withCheckedThrowingContinuation { continuation in |
|
|
|
getCurrentLocation { result in |
|
|
|
/// 同步获取位置 |
|
|
|
private func syncGetLocation(completion: @escaping (Result<[String: Any], Error>) -> Void) { |
|
|
|
// 检查权限 |
|
|
|
guard checkLocationPermission() else { |
|
|
|
print("[LocationService] 无位置权限,尝试请求权限") |
|
|
|
requestLocationPermission { [weak self] result in |
|
|
|
switch result { |
|
|
|
case .success(let locationInfo): |
|
|
|
// 从返回的字典中提取位置信息 |
|
|
|
if let latStr = locationInfo["user_lat"] as? String, |
|
|
|
let lngStr = locationInfo["user_lng"] as? String, |
|
|
|
let latitude = Double(latStr), |
|
|
|
let longitude = Double(lngStr), |
|
|
|
let address = locationInfo["user_location"] as? String { |
|
|
|
|
|
|
|
let locationData = LocationData( |
|
|
|
latitude: latitude, |
|
|
|
longitude: longitude, |
|
|
|
address: address, |
|
|
|
timestamp: Date().timeIntervalSince1970 * 1000 |
|
|
|
) |
|
|
|
continuation.resume(returning: locationData) |
|
|
|
case .success(let granted): |
|
|
|
if granted { |
|
|
|
print("[LocationService] 权限获取成功,重新获取位置") |
|
|
|
self?.syncGetLocation(completion: completion) |
|
|
|
} else { |
|
|
|
continuation.resume(throwing: NSError(domain: "LocationService", code: -5, userInfo: [NSLocalizedDescriptionKey: "位置数据格式错误"])) |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -1, userInfo: [NSLocalizedDescriptionKey: "位置权限被拒绝"]))) |
|
|
|
} |
|
|
|
case .failure(let error): |
|
|
|
continuation.resume(throwing: error) |
|
|
|
completion(.failure(error)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 获取当前位置(供其他iOS服务使用) |
|
|
|
public func requestLocation(callback: LocationCallback) { |
|
|
|
if !checkPermissions() { |
|
|
|
callback.onLocationError(errorCode: -2, errorMessage: "没有定位权限") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if !initialized { |
|
|
|
callback.onLocationError(errorCode: -3, errorMessage: "定位服务未初始化") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 添加到回调列表 |
|
|
|
serviceCallbacks.append(callback) |
|
|
|
|
|
|
|
// 如果没有正在进行的定位请求,开始定位 |
|
|
|
if currentLocationCallback == nil && serviceCallbacks.count == 1 { |
|
|
|
locationManager?.requestLocation() |
|
|
|
// 有权限,直接获取位置 |
|
|
|
requestLocationUpdate { [weak self] result in |
|
|
|
switch result { |
|
|
|
case .success(let locationData): |
|
|
|
print("[LocationService] 同步获取位置成功") |
|
|
|
self?.cachedLocationData = locationData |
|
|
|
let locationInfo = self?.formatLocationData(locationData) ?? [:] |
|
|
|
completion(.success(locationInfo)) |
|
|
|
case .failure(let error): |
|
|
|
print("[LocationService] 同步获取位置失败: \(error.localizedDescription)") |
|
|
|
completion(.failure(error)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 同步获取缓存的位置信息(供其他服务使用) |
|
|
|
/// 注意:这个方法返回的可能是过期的位置信息 |
|
|
|
public func getCachedLocationData() -> LocationData? { |
|
|
|
// 优先返回内存中的缓存 |
|
|
|
if let cached = cachedLocationData { |
|
|
|
return cached |
|
|
|
} |
|
|
|
|
|
|
|
// 从UserDefaults中读取缓存 |
|
|
|
return loadCachedLocationFromUserDefaults() |
|
|
|
/// 检查位置权限 - 使用缓存的状态 |
|
|
|
private func checkLocationPermission() -> Bool { |
|
|
|
return authorizationStatus == .authorizedWhenInUse || authorizationStatus == .authorizedAlways |
|
|
|
} |
|
|
|
|
|
|
|
private func saveCachedLocationToUserDefaults(_ locationData: LocationData) { |
|
|
|
do { |
|
|
|
let encoder = JSONEncoder() |
|
|
|
let data = try encoder.encode(locationData) |
|
|
|
UserDefaults.standard.set(data, forKey: "latitude") |
|
|
|
UserDefaults.standard.set(String(locationData.latitude), forKey: "latitude") |
|
|
|
UserDefaults.standard.set(String(locationData.longitude), forKey: "longitude") |
|
|
|
UserDefaults.standard.set(locationData.address, forKey: "address") |
|
|
|
UserDefaults.standard.set(Double(locationData.timestamp), forKey: "timestamp") |
|
|
|
UserDefaults.standard.synchronize() |
|
|
|
} catch { |
|
|
|
print("\(LocationService.TAG): 保存位置缓存失败: \(error.localizedDescription)") |
|
|
|
/// 请求位置权限 - 异步处理 |
|
|
|
private func requestLocationPermission(completion: @escaping (Result<Bool, Error>) -> Void) { |
|
|
|
print("[LocationService] 当前缓存的权限状态: \(authorizationStatus.rawValue)") |
|
|
|
|
|
|
|
switch authorizationStatus { |
|
|
|
case .notDetermined: |
|
|
|
print("[LocationService] 请求位置权限") |
|
|
|
// 保存回调,等待权限结果 |
|
|
|
permissionCallback = completion |
|
|
|
DispatchQueue.main.async { [weak self] in |
|
|
|
self?.locationManager?.requestWhenInUseAuthorization() |
|
|
|
} |
|
|
|
case .denied, .restricted: |
|
|
|
print("[LocationService] 位置权限被拒绝或受限") |
|
|
|
completion(.success(false)) |
|
|
|
case .authorizedWhenInUse, .authorizedAlways: |
|
|
|
print("[LocationService] 已有位置权限") |
|
|
|
completion(.success(true)) |
|
|
|
@unknown default: |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -2, userInfo: [NSLocalizedDescriptionKey: "未知权限状态"]))) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
private func loadCachedLocationFromUserDefaults() -> LocationData? { |
|
|
|
do { |
|
|
|
guard let latitudeStr = UserDefaults.standard.string(forKey: "latitude"), |
|
|
|
let longitudeStr = UserDefaults.standard.string(forKey: "longitude"), |
|
|
|
let latitude = Double(latitudeStr), |
|
|
|
let longitude = Double(longitudeStr) else { |
|
|
|
return nil |
|
|
|
/// 请求位置更新 - 优化版本 |
|
|
|
private func requestLocationUpdate(completion: @escaping (Result<LocationData, Error>) -> Void) { |
|
|
|
DispatchQueue.main.async { [weak self] in |
|
|
|
guard let self = self else { return } |
|
|
|
|
|
|
|
guard let locationManager = self.locationManager else { |
|
|
|
print("[LocationService] 错误:LocationManager 未初始化") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -3, userInfo: [NSLocalizedDescriptionKey: "LocationManager 未初始化"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
let address = UserDefaults.standard.string(forKey: "address") ?? "未知地址" |
|
|
|
let timestampDouble = UserDefaults.standard.double(forKey: "timestamp") |
|
|
|
// 检查是否已有请求在进行 |
|
|
|
if self.currentLocationCallback != nil { |
|
|
|
print("[LocationService] 错误:位置请求正在进行中,拒绝新请求") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -4, userInfo: [NSLocalizedDescriptionKey: "位置请求正在进行中"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if timestampDouble == 0 { return nil } |
|
|
|
// 使用缓存的状态信息 |
|
|
|
print("[LocationService] 开始位置请求") |
|
|
|
print("[LocationService] 缓存的权限状态: \(self.authorizationStatus.rawValue)") |
|
|
|
print("[LocationService] 缓存的位置服务状态: \(self.isLocationServicesEnabled)") |
|
|
|
print("[LocationService] 当前线程: \(Thread.current)") |
|
|
|
print("[LocationService] 是否主线程: \(Thread.isMainThread)") |
|
|
|
|
|
|
|
return LocationData( |
|
|
|
latitude: latitude, |
|
|
|
longitude: longitude, |
|
|
|
address: address, |
|
|
|
timestamp: TimeInterval(timestampDouble) |
|
|
|
) |
|
|
|
} catch { |
|
|
|
print("\(LocationService.TAG): 读取位置缓存失败: \(error.localizedDescription)") |
|
|
|
return nil |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 停止定位服务 |
|
|
|
public func stop() { |
|
|
|
locationManager?.stopUpdatingLocation() |
|
|
|
locationManager = nil |
|
|
|
currentLocationCallback = nil |
|
|
|
permissionRequestCallback = nil |
|
|
|
serviceCallbacks.removeAll() |
|
|
|
initialized = false |
|
|
|
stopPermissionMonitor() |
|
|
|
} |
|
|
|
|
|
|
|
private func handleLocationResult(_ location: CLLocation?, error: Error?) { |
|
|
|
// 处理Flutter回调 |
|
|
|
let flutterCallback = currentLocationCallback |
|
|
|
currentLocationCallback = nil |
|
|
|
|
|
|
|
if let location = location, error == nil { |
|
|
|
print("\(LocationService.TAG): 定位成功: \(location.coordinate.latitude), \(location.coordinate.longitude)") |
|
|
|
// 验证权限状态 |
|
|
|
if !self.checkLocationPermission() { |
|
|
|
print("[LocationService] 错误:无位置权限") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -5, userInfo: [NSLocalizedDescriptionKey: "无位置权限"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 进行逆地理编码获取地址 |
|
|
|
let geocoder = CLGeocoder() |
|
|
|
geocoder.reverseGeocodeLocation(location) { [weak self] placemarks, geocodeError in |
|
|
|
guard let self = self else { return } |
|
|
|
|
|
|
|
let address = placemarks?.first?.name ?? "未知地址" |
|
|
|
|
|
|
|
// 缓存位置数据 |
|
|
|
let locationData = LocationData( |
|
|
|
latitude: location.coordinate.latitude, |
|
|
|
longitude: location.coordinate.longitude, |
|
|
|
address: address, |
|
|
|
timestamp: TimeInterval(Date().timeIntervalSince1970) * 1000 |
|
|
|
) |
|
|
|
self.cachedLocationData = locationData |
|
|
|
self.saveCachedLocationToUserDefaults(locationData) |
|
|
|
|
|
|
|
// 通知Flutter |
|
|
|
if let callback = flutterCallback { |
|
|
|
let result: [String: Any] = [ |
|
|
|
"user_location": address, |
|
|
|
"user_lat": String(location.coordinate.latitude), |
|
|
|
"user_lng": String(location.coordinate.longitude) |
|
|
|
] |
|
|
|
callback(.success(result)) |
|
|
|
} |
|
|
|
|
|
|
|
// 通知其他iOS服务 |
|
|
|
self.serviceCallbacks.forEach { callback in |
|
|
|
callback.onLocationSuccess( |
|
|
|
latitude: location.coordinate.latitude, |
|
|
|
longitude: location.coordinate.longitude, |
|
|
|
address: address |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
// 清空服务回调列表(单次定位) |
|
|
|
self.serviceCallbacks.removeAll() |
|
|
|
if !self.isLocationServicesEnabled { |
|
|
|
print("[LocationService] 错误:位置服务未启用") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -6, userInfo: [NSLocalizedDescriptionKey: "位置服务未启用"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
} else { |
|
|
|
let errorMessage = error?.localizedDescription ?? "未知错误" |
|
|
|
print("\(LocationService.TAG): 定位失败: \(errorMessage)") |
|
|
|
|
|
|
|
// 通知Flutter |
|
|
|
if let callback = flutterCallback { |
|
|
|
callback(.failure(NSError(domain: "LocationService", code: -1, userInfo: [NSLocalizedDescriptionKey: "定位失败: \(errorMessage)"]))) |
|
|
|
// 强制重新设置 delegate |
|
|
|
if locationManager.delegate == nil { |
|
|
|
print("[LocationService] 警告:Delegate 为空,重新设置") |
|
|
|
locationManager.delegate = self |
|
|
|
} |
|
|
|
|
|
|
|
// 通知其他iOS服务 |
|
|
|
serviceCallbacks.forEach { callback in |
|
|
|
callback.onLocationError(errorCode: -1, errorMessage: errorMessage) |
|
|
|
// 验证 delegate |
|
|
|
if locationManager.delegate === self { |
|
|
|
print("[LocationService] Delegate 验证成功") |
|
|
|
} else { |
|
|
|
print("[LocationService] 错误:Delegate 设置失败") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -8, userInfo: [NSLocalizedDescriptionKey: "Delegate 设置失败"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 清空服务回调列表 |
|
|
|
serviceCallbacks.removeAll() |
|
|
|
// 设置回调 |
|
|
|
self.currentLocationCallback = { result in |
|
|
|
switch result { |
|
|
|
case .success(let locationInfo): |
|
|
|
print("[LocationService] 位置回调成功,开始解析数据") |
|
|
|
if let latStr = locationInfo["user_lat"] as? String, |
|
|
|
let lngStr = locationInfo["user_lng"] as? String, |
|
|
|
let latitude = Double(latStr), |
|
|
|
let longitude = Double(lngStr) { |
|
|
|
|
|
|
|
print("[LocationService] 位置数据解析成功: lat=\(latitude), lng=\(longitude)") |
|
|
|
let locationData = LocationData( |
|
|
|
latitude: latitude, |
|
|
|
longitude: longitude, |
|
|
|
address: "", |
|
|
|
timestamp: Date().timeIntervalSince1970 * 1000 |
|
|
|
) |
|
|
|
completion(.success(locationData)) |
|
|
|
} else { |
|
|
|
print("[LocationService] 错误:位置数据格式错误,原始数据: \(locationInfo)") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -7, userInfo: [NSLocalizedDescriptionKey: "位置数据格式错误"]))) |
|
|
|
} |
|
|
|
case .failure(let error): |
|
|
|
print("[LocationService] 位置回调失败: \(error.localizedDescription)") |
|
|
|
completion(.failure(error)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
print("[LocationService] 调用 locationManager.requestLocation()") |
|
|
|
locationManager.requestLocation() |
|
|
|
print("[LocationService] requestLocation() 调用完成,等待回调") |
|
|
|
|
|
|
|
// 30秒超时机制 |
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 30) { |
|
|
|
if self.currentLocationCallback != nil { |
|
|
|
print("[LocationService] 位置请求超时") |
|
|
|
let callback = self.currentLocationCallback |
|
|
|
self.currentLocationCallback = nil |
|
|
|
callback?(.failure(NSError(domain: "LocationService", code: -9, userInfo: [NSLocalizedDescriptionKey: "位置请求超时"]))) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 格式化位置数据 |
|
|
|
private func formatLocationData(_ locationData: LocationData) -> [String: Any] { |
|
|
|
return [ |
|
|
|
"user_lat": String(locationData.latitude), |
|
|
|
"user_lng": String(locationData.longitude), |
|
|
|
"user_location": locationData.address, |
|
|
|
"timestamp": locationData.timestamp |
|
|
|
] |
|
|
|
} |
|
|
|
|
|
|
|
// MARK: - 权限回调 |
|
|
|
private var permissionCallback: ((Result<Bool, Error>) -> Void)? |
|
|
|
} |
|
|
|
|
|
|
|
// MARK: - CLLocationManagerDelegate |
|
|
|
extension LocationService: CLLocationManagerDelegate { |
|
|
|
// 替换 didUpdateLocations 方法中的逆地理编码部分 |
|
|
|
public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { |
|
|
|
guard let location = locations.last else { return } |
|
|
|
handleLocationResult(location, error: nil) |
|
|
|
print("[LocationService] didUpdateLocations 被调用,位置数量: \(locations.count)") |
|
|
|
|
|
|
|
guard let location = locations.last else { |
|
|
|
print("[LocationService] 错误:locations 数组为空") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
print("[LocationService] 位置更新成功: lat=\(location.coordinate.latitude), lng=\(location.coordinate.longitude)") |
|
|
|
print("[LocationService] 位置精度: \(location.horizontalAccuracy)m") |
|
|
|
|
|
|
|
// 直接使用经纬度,不进行逆地理编码 |
|
|
|
let locationInfo: [String: Any] = [ |
|
|
|
"user_lat": String(location.coordinate.latitude), |
|
|
|
"user_lng": String(location.coordinate.longitude), |
|
|
|
"timestamp": Date().timeIntervalSince1970 * 1000 |
|
|
|
] |
|
|
|
|
|
|
|
print("[LocationService] 准备调用位置回调") |
|
|
|
// 调用回调 |
|
|
|
let callback = currentLocationCallback |
|
|
|
currentLocationCallback = nil |
|
|
|
callback?(.success(locationInfo)) |
|
|
|
print("[LocationService] 位置回调已调用") |
|
|
|
} |
|
|
|
|
|
|
|
public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { |
|
|
|
handleLocationResult(nil, error: error) |
|
|
|
print("[LocationService] didFailWithError 被调用") |
|
|
|
print("[LocationService] 位置获取失败: \(error.localizedDescription)") |
|
|
|
print("[LocationService] 错误代码: \((error as NSError).code)") |
|
|
|
print("[LocationService] 错误域: \((error as NSError).domain)") |
|
|
|
|
|
|
|
let callback = currentLocationCallback |
|
|
|
currentLocationCallback = nil |
|
|
|
print("[LocationService] 准备调用错误回调") |
|
|
|
callback?(.failure(error)) |
|
|
|
print("[LocationService] 错误回调已调用") |
|
|
|
} |
|
|
|
|
|
|
|
public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { |
|
|
|
print("\(LocationService.TAG): 定位权限状态变更: \(status.rawValue)") |
|
|
|
print("[LocationService] didChangeAuthorization 被调用") |
|
|
|
print("[LocationService] 权限状态变更: \(status.rawValue) (\(authorizationStatusString(status)))") |
|
|
|
|
|
|
|
// 更新缓存的状态 |
|
|
|
authorizationStatus = status |
|
|
|
isLocationServicesEnabled = CLLocationManager.locationServicesEnabled() |
|
|
|
|
|
|
|
print("[LocationService] 更新缓存状态 - 权限: \(authorizationStatus.rawValue), 服务启用: \(isLocationServicesEnabled)") |
|
|
|
|
|
|
|
guard let callback = permissionCallback else { |
|
|
|
print("[LocationService] 无权限回调,忽略权限变更") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
switch status { |
|
|
|
case .authorizedWhenInUse, .authorizedAlways: |
|
|
|
if !initialized { |
|
|
|
initialize() |
|
|
|
} |
|
|
|
permissionRequestCallback?(.success(["granted": true])) |
|
|
|
permissionRequestCallback = nil |
|
|
|
print("[LocationService] 权限获取成功") |
|
|
|
permissionCallback = nil |
|
|
|
callback(.success(true)) |
|
|
|
case .denied, .restricted: |
|
|
|
permissionRequestCallback?(.success(["granted": false])) |
|
|
|
permissionRequestCallback = nil |
|
|
|
print("[LocationService] 权限被拒绝或受限") |
|
|
|
permissionCallback = nil |
|
|
|
callback(.success(false)) |
|
|
|
case .notDetermined: |
|
|
|
break |
|
|
|
print("[LocationService] 权限状态仍未确定,继续等待") |
|
|
|
// 继续等待用户选择 |
|
|
|
permissionCallback = callback |
|
|
|
@unknown default: |
|
|
|
break |
|
|
|
print("[LocationService] 未知权限状态") |
|
|
|
permissionCallback = nil |
|
|
|
callback(.failure(NSError(domain: "LocationService", code: -10, userInfo: [NSLocalizedDescriptionKey: "未知权限状态"]))) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// 辅助方法:将权限状态转换为可读字符串 |
|
|
|
private func authorizationStatusString(_ status: CLAuthorizationStatus) -> String { |
|
|
|
switch status { |
|
|
|
case .notDetermined: return "notDetermined" |
|
|
|
case .restricted: return "restricted" |
|
|
|
case .denied: return "denied" |
|
|
|
case .authorizedAlways: return "authorizedAlways" |
|
|
|
case .authorizedWhenInUse: return "authorizedWhenInUse" |
|
|
|
@unknown default: return "unknown" |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// Remove the duplicate LocationData definition from here |
|
|
|
// The LocationData struct is already defined in LocationData.swift |
|
|
|
|