|
|
|
@ -23,37 +23,33 @@ public class LocationService: NSObject { |
|
|
|
private var authorizationStatus: CLAuthorizationStatus = .notDetermined |
|
|
|
private var isLocationServicesEnabled: Bool = false |
|
|
|
|
|
|
|
// 高精度定位属性 |
|
|
|
private var locationAttempts: Int = 0 |
|
|
|
private let maxLocationAttempts: Int = 3 |
|
|
|
private let requiredAccuracy: CLLocationAccuracy = 10.0 // 要求精度在10米以内 |
|
|
|
private var bestLocation: CLLocation? |
|
|
|
private var locationTimer: Timer? |
|
|
|
|
|
|
|
// MARK: - 权限回调 |
|
|
|
private var permissionCallback: ((Result<Bool, Error>) -> Void)? |
|
|
|
|
|
|
|
private override init() { |
|
|
|
super.init() |
|
|
|
setupLocationManager() |
|
|
|
} |
|
|
|
|
|
|
|
private func setupLocationManager() { |
|
|
|
DispatchQueue.main.async { [weak self] in |
|
|
|
self?.locationManager = CLLocationManager() |
|
|
|
self?.locationManager?.delegate = self |
|
|
|
self?.locationManager?.desiredAccuracy = kCLLocationAccuracyBest |
|
|
|
self?.locationManager?.distanceFilter = 10 |
|
|
|
|
|
|
|
// 不需要手动获取状态,delegate 方法会自动被调用 |
|
|
|
// 高精度定位设置 |
|
|
|
self?.locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation // 最高精度 |
|
|
|
self?.locationManager?.distanceFilter = 1 // 降低距离过滤器,更敏感 |
|
|
|
|
|
|
|
print("[LocationService] LocationManager 初始化完成,等待权限状态回调") |
|
|
|
} |
|
|
|
} |
|
|
|
// private func setupLocationManager() { |
|
|
|
// 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)") |
|
|
|
// } |
|
|
|
// } |
|
|
|
|
|
|
|
/// 获取当前位置 - 主要接口 |
|
|
|
public func getCurrentLocation(completion: @escaping (Result<[String: Any], Error>) -> Void) { |
|
|
|
@ -98,20 +94,14 @@ public class LocationService: NSObject { |
|
|
|
/// 异步更新位置缓存 |
|
|
|
private func asyncUpdateLocation() { |
|
|
|
// 检查权限 |
|
|
|
guard checkLocationPermission() else { |
|
|
|
print("[LocationService] 异步更新失败:无位置权限") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 异步请求位置更新 |
|
|
|
DispatchQueue.global(qos: .background).async { [weak self] in |
|
|
|
self?.requestLocationUpdate { result in |
|
|
|
if checkLocationPermission() { |
|
|
|
requestHighAccuracyLocation { [weak self] result in |
|
|
|
switch result { |
|
|
|
case .success(let locationData): |
|
|
|
print("[LocationService] 异步更新位置缓存成功") |
|
|
|
self?.cachedLocationData = locationData |
|
|
|
print("[LocationService] 异步更新缓存成功") |
|
|
|
case .failure(let error): |
|
|
|
print("[LocationService] 异步更新位置缓存失败: \(error.localizedDescription)") |
|
|
|
print("[LocationService] 异步更新缓存失败: \(error.localizedDescription)") |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -119,14 +109,22 @@ public class LocationService: NSObject { |
|
|
|
|
|
|
|
/// 同步获取位置 |
|
|
|
private func syncGetLocation(completion: @escaping (Result<[String: Any], Error>) -> Void) { |
|
|
|
// 检查权限 |
|
|
|
guard checkLocationPermission() else { |
|
|
|
print("[LocationService] 无位置权限,尝试请求权限") |
|
|
|
if checkLocationPermission() { |
|
|
|
requestHighAccuracyLocation { [weak self] result in |
|
|
|
switch result { |
|
|
|
case .success(let locationData): |
|
|
|
self?.cachedLocationData = locationData |
|
|
|
let locationInfo = self?.formatLocationData(locationData) ?? [:] |
|
|
|
completion(.success(locationInfo)) |
|
|
|
case .failure(let error): |
|
|
|
completion(.failure(error)) |
|
|
|
} |
|
|
|
} |
|
|
|
} else { |
|
|
|
requestLocationPermission { [weak self] result in |
|
|
|
switch result { |
|
|
|
case .success(let granted): |
|
|
|
if granted { |
|
|
|
print("[LocationService] 权限获取成功,重新获取位置") |
|
|
|
self?.syncGetLocation(completion: completion) |
|
|
|
} else { |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -1, userInfo: [NSLocalizedDescriptionKey: "位置权限被拒绝"]))) |
|
|
|
@ -135,116 +133,76 @@ public class LocationService: NSObject { |
|
|
|
completion(.failure(error)) |
|
|
|
} |
|
|
|
} |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 有权限,直接获取位置 |
|
|
|
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)) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 检查位置权限 - 使用缓存的状态 |
|
|
|
/// 检查位置权限 |
|
|
|
private func checkLocationPermission() -> Bool { |
|
|
|
return authorizationStatus == .authorizedWhenInUse || authorizationStatus == .authorizedAlways |
|
|
|
} |
|
|
|
|
|
|
|
/// 请求位置权限 - 异步处理 |
|
|
|
/// 请求位置权限 |
|
|
|
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() |
|
|
|
guard let self = self else { return } |
|
|
|
|
|
|
|
guard let locationManager = self.locationManager else { |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -3, userInfo: [NSLocalizedDescriptionKey: "LocationManager 未初始化"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 设置权限回调 |
|
|
|
self.permissionCallback = completion |
|
|
|
|
|
|
|
// 请求权限 |
|
|
|
switch self.authorizationStatus { |
|
|
|
case .notDetermined: |
|
|
|
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 requestLocationUpdate(completion: @escaping (Result<LocationData, Error>) -> Void) { |
|
|
|
/// 高精度定位方法 |
|
|
|
private func requestHighAccuracyLocation(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 |
|
|
|
} |
|
|
|
|
|
|
|
// 检查是否已有请求在进行 |
|
|
|
if self.currentLocationCallback != nil { |
|
|
|
print("[LocationService] 错误:位置请求正在进行中,拒绝新请求") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -4, userInfo: [NSLocalizedDescriptionKey: "位置请求正在进行中"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 使用缓存的状态信息 |
|
|
|
// print("[LocationService] 开始位置请求") |
|
|
|
// print("[LocationService] 缓存的权限状态: \(self.authorizationStatus.rawValue)") |
|
|
|
// print("[LocationService] 缓存的位置服务状态: \(self.isLocationServicesEnabled)") |
|
|
|
// print("[LocationService] 当前线程: \(Thread.current)") |
|
|
|
// print("[LocationService] 是否主线程: \(Thread.isMainThread)") |
|
|
|
|
|
|
|
// 验证权限状态 |
|
|
|
// 检查权限 |
|
|
|
if !self.checkLocationPermission() { |
|
|
|
print("[LocationService] 错误:无位置权限") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -5, userInfo: [NSLocalizedDescriptionKey: "无位置权限"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
if !self.isLocationServicesEnabled { |
|
|
|
print("[LocationService] 错误:位置服务未启用") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -6, userInfo: [NSLocalizedDescriptionKey: "位置服务未启用"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 强制重新设置 delegate |
|
|
|
if locationManager.delegate == nil { |
|
|
|
print("[LocationService] 警告:Delegate 为空,重新设置") |
|
|
|
locationManager.delegate = self |
|
|
|
} |
|
|
|
|
|
|
|
// 验证 delegate |
|
|
|
if locationManager.delegate === self { |
|
|
|
print("[LocationService] Delegate 验证成功") |
|
|
|
} else { |
|
|
|
print("[LocationService] 错误:Delegate 设置失败") |
|
|
|
completion(.failure(NSError(domain: "LocationService", code: -8, userInfo: [NSLocalizedDescriptionKey: "Delegate 设置失败"]))) |
|
|
|
return |
|
|
|
} |
|
|
|
// 重置状态 |
|
|
|
self.locationAttempts = 0 |
|
|
|
self.bestLocation = nil |
|
|
|
|
|
|
|
// 设置回调 |
|
|
|
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, |
|
|
|
@ -252,29 +210,59 @@ public class LocationService: NSObject { |
|
|
|
) |
|
|
|
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() 调用完成,等待回调") |
|
|
|
print("[LocationService] 开始高精度连续定位") |
|
|
|
// 开始连续定位 |
|
|
|
locationManager.startUpdatingLocation() |
|
|
|
|
|
|
|
// 30秒超时机制 |
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 30) { |
|
|
|
if self.currentLocationCallback != nil { |
|
|
|
print("[LocationService] 位置请求超时") |
|
|
|
// 设置超时定时器(15秒) |
|
|
|
self.locationTimer = Timer.scheduledTimer(withTimeInterval: 15.0, repeats: false) { _ in |
|
|
|
self.stopLocationUpdates() |
|
|
|
if let bestLocation = self.bestLocation { |
|
|
|
self.processLocation(bestLocation) |
|
|
|
} else { |
|
|
|
let callback = self.currentLocationCallback |
|
|
|
self.currentLocationCallback = nil |
|
|
|
callback?(.failure(NSError(domain: "LocationService", code: -9, userInfo: [NSLocalizedDescriptionKey: "位置请求超时"]))) |
|
|
|
callback?(.failure(NSError(domain: "LocationService", code: -9, userInfo: [NSLocalizedDescriptionKey: "无法获取满足精度要求的位置"]))) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// 停止位置更新 |
|
|
|
private func stopLocationUpdates() { |
|
|
|
locationManager?.stopUpdatingLocation() |
|
|
|
locationTimer?.invalidate() |
|
|
|
locationTimer = nil |
|
|
|
} |
|
|
|
|
|
|
|
/// 处理位置数据 |
|
|
|
private func processLocation(_ location: CLLocation) { |
|
|
|
let locationInfo: [String: Any] = [ |
|
|
|
"user_lat": String(location.coordinate.latitude), |
|
|
|
"user_lng": String(location.coordinate.longitude), |
|
|
|
"timestamp": Date().timeIntervalSince1970 * 1000, |
|
|
|
"accuracy": location.horizontalAccuracy // 添加精度信息 |
|
|
|
] |
|
|
|
|
|
|
|
print("[LocationService] 处理最终位置,精度: \(location.horizontalAccuracy)m") |
|
|
|
|
|
|
|
// 更新缓存 |
|
|
|
cachedLocationData = LocationData( |
|
|
|
latitude: location.coordinate.latitude, |
|
|
|
longitude: location.coordinate.longitude, |
|
|
|
timestamp: Date().timeIntervalSince1970 * 1000 |
|
|
|
) |
|
|
|
|
|
|
|
let callback = currentLocationCallback |
|
|
|
currentLocationCallback = nil |
|
|
|
callback?(.success(locationInfo)) |
|
|
|
} |
|
|
|
|
|
|
|
/// 格式化位置数据 |
|
|
|
@ -285,14 +273,11 @@ public class LocationService: NSObject { |
|
|
|
"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]) { |
|
|
|
print("[LocationService] didUpdateLocations 被调用,位置数量: \(locations.count)") |
|
|
|
|
|
|
|
@ -301,22 +286,47 @@ extension LocationService: CLLocationManagerDelegate { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
print("[LocationService] 位置更新成功: lat=\(location.coordinate.latitude), lng=\(location.coordinate.longitude)") |
|
|
|
print("[LocationService] 位置精度: \(location.horizontalAccuracy)m") |
|
|
|
print("[LocationService] 位置更新: lat=\(location.coordinate.latitude), lng=\(location.coordinate.longitude)") |
|
|
|
print("[LocationService] 水平精度: \(location.horizontalAccuracy)m, 垂直精度: \(location.verticalAccuracy)m") |
|
|
|
print("[LocationService] 位置时间: \(location.timestamp)") |
|
|
|
|
|
|
|
// 直接使用经纬度,不进行逆地理编码 |
|
|
|
let locationInfo: [String: Any] = [ |
|
|
|
"user_lat": String(location.coordinate.latitude), |
|
|
|
"user_lng": String(location.coordinate.longitude), |
|
|
|
"timestamp": Date().timeIntervalSince1970 * 1000 |
|
|
|
] |
|
|
|
// 过滤无效位置 |
|
|
|
guard location.horizontalAccuracy >= 0 else { |
|
|
|
print("[LocationService] 位置精度无效,忽略此次更新") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
print("[LocationService] 准备调用位置回调") |
|
|
|
// 调用回调 |
|
|
|
let callback = currentLocationCallback |
|
|
|
currentLocationCallback = nil |
|
|
|
callback?(.success(locationInfo)) |
|
|
|
print("[LocationService] 位置回调已调用") |
|
|
|
// 过滤过旧的位置(超过5秒) |
|
|
|
let locationAge = -location.timestamp.timeIntervalSinceNow |
|
|
|
guard locationAge < 5.0 else { |
|
|
|
print("[LocationService] 位置数据过旧(\(locationAge)秒),忽略") |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
locationAttempts += 1 |
|
|
|
|
|
|
|
// 检查是否满足精度要求 |
|
|
|
if location.horizontalAccuracy <= requiredAccuracy { |
|
|
|
print("[LocationService] 获得高精度位置,精度: \(location.horizontalAccuracy)m") |
|
|
|
stopLocationUpdates() |
|
|
|
processLocation(location) |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 保存最佳位置 |
|
|
|
if bestLocation == nil || location.horizontalAccuracy < bestLocation!.horizontalAccuracy { |
|
|
|
bestLocation = location |
|
|
|
print("[LocationService] 更新最佳位置,精度: \(location.horizontalAccuracy)m") |
|
|
|
} |
|
|
|
|
|
|
|
// 达到最大尝试次数,使用最佳位置 |
|
|
|
if locationAttempts >= maxLocationAttempts { |
|
|
|
print("[LocationService] 达到最大尝试次数,使用最佳位置") |
|
|
|
stopLocationUpdates() |
|
|
|
if let bestLocation = bestLocation { |
|
|
|
processLocation(bestLocation) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { |
|
|
|
@ -325,11 +335,10 @@ extension LocationService: CLLocationManagerDelegate { |
|
|
|
print("[LocationService] 错误代码: \((error as NSError).code)") |
|
|
|
print("[LocationService] 错误域: \((error as NSError).domain)") |
|
|
|
|
|
|
|
stopLocationUpdates() |
|
|
|
let callback = currentLocationCallback |
|
|
|
currentLocationCallback = nil |
|
|
|
print("[LocationService] 准备调用错误回调") |
|
|
|
callback?(.failure(error)) |
|
|
|
print("[LocationService] 错误回调已调用") |
|
|
|
} |
|
|
|
|
|
|
|
public func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) { |
|
|
|
|