From 4ab2da85cb9327ec3fb1f3a587f5034a215074a2 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Mon, 11 Aug 2025 10:34:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E5=AE=9A=E4=BD=8D=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../chat_api/SystemFunctionHandler.kt | 1 + .../chat_api/SystemFunctionHandler.swift | 2 + .../location_service/LocationService.swift | 273 +++++++++--------- pubspec.yaml | 2 +- 4 files changed, 145 insertions(+), 133 deletions(-) diff --git a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt index 4ecb86ffe..2af198233 100644 --- a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt +++ b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt @@ -1181,6 +1181,7 @@ private class GetCurrentLocationHandler(private val context: Context?) : Functio put("latitude", cachedLocation.latitude) put("longitude", cachedLocation.longitude) put("address", cachedLocation.address) + put("location", "${cachedLocation.latitude},${cachedLocation.longitude}") put("source", "cache") put("timestamp", cachedLocation.timestamp) put("cacheAgeMinutes", cacheAgeMinutes) diff --git a/local_plugins/chat_api/ios/chat_api/Sources/chat_api/SystemFunctionHandler.swift b/local_plugins/chat_api/ios/chat_api/Sources/chat_api/SystemFunctionHandler.swift index c6a35e433..b0c19e4a6 100644 --- a/local_plugins/chat_api/ios/chat_api/Sources/chat_api/SystemFunctionHandler.swift +++ b/local_plugins/chat_api/ios/chat_api/Sources/chat_api/SystemFunctionHandler.swift @@ -461,6 +461,7 @@ private class GetCurrentLocationHandler: FunctionHandler { // 解析位置数据 guard let latStr = locationInfo["user_lat"] as? String, let lngStr = locationInfo["user_lng"] as? String, + let latitude = Double(latStr), let longitude = Double(lngStr) else { print("[GetCurrentLocationHandler] 位置数据格式错误") @@ -491,6 +492,7 @@ private class GetCurrentLocationHandler: FunctionHandler { "data": [ "latitude": latitude, "longitude": longitude, + "location": "\(latitude),\(longitude)", "timestamp": Date().timeIntervalSince1970 * 1000 ] ] diff --git a/local_plugins/location_service/ios/location_service/Sources/location_service/LocationService.swift b/local_plugins/location_service/ios/location_service/Sources/location_service/LocationService.swift index 906789434..53c23686d 100644 --- a/local_plugins/location_service/ios/location_service/Sources/location_service/LocationService.swift +++ b/local_plugins/location_service/ios/location_service/Sources/location_service/LocationService.swift @@ -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) -> 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) -> Void) { - print("[LocationService] 当前缓存的权限状态: \(authorizationStatus.rawValue)") - - switch authorizationStatus { - case .notDetermined: - print("[LocationService] 请求位置权限") - // 保存回调,等待权限结果 - permissionCallback = completion - DispatchQueue.main.async { [weak self] in - self?.locationManager?.requestWhenInUseAuthorization() + DispatchQueue.main.async { [weak self] in + 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: + completion(.success(false)) + case .authorizedWhenInUse, .authorizedAlways: + completion(.success(true)) + @unknown default: + completion(.failure(NSError(domain: "LocationService", code: -2, userInfo: [NSLocalizedDescriptionKey: "未知权限状态"]))) } - 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) -> Void) { + /// 高精度定位方法 + private func requestHighAccuracyLocation(completion: @escaping (Result) -> 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,31 +210,61 @@ 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)) + } + /// 格式化位置数据 private func formatLocationData(_ locationData: LocationData) -> [String: Any] { return [ @@ -285,14 +273,11 @@ public class LocationService: NSObject { "timestamp": locationData.timestamp ] } - - // MARK: - 权限回调 - private var permissionCallback: ((Result) -> 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) { diff --git a/pubspec.yaml b/pubspec.yaml index 17c0f91a2..615a2346a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: voitrans description: "Voitrans - AI Voice Assistant." publish_to: "none" -version: 1.0.6+20 +version: 1.0.7+20 environment: sdk: ">=3.3.0 <4.0.0"