Browse Source

上传定位优化逻辑

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
4ab2da85cb
  1. 1
      local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/SystemFunctionHandler.kt
  2. 2
      local_plugins/chat_api/ios/chat_api/Sources/chat_api/SystemFunctionHandler.swift
  3. 273
      local_plugins/location_service/ios/location_service/Sources/location_service/LocationService.swift
  4. 2
      pubspec.yaml

1
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("latitude", cachedLocation.latitude)
put("longitude", cachedLocation.longitude) put("longitude", cachedLocation.longitude)
put("address", cachedLocation.address) put("address", cachedLocation.address)
put("location", "${cachedLocation.latitude},${cachedLocation.longitude}")
put("source", "cache") put("source", "cache")
put("timestamp", cachedLocation.timestamp) put("timestamp", cachedLocation.timestamp)
put("cacheAgeMinutes", cacheAgeMinutes) put("cacheAgeMinutes", cacheAgeMinutes)

2
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, guard let latStr = locationInfo["user_lat"] as? String,
let lngStr = locationInfo["user_lng"] as? String, let lngStr = locationInfo["user_lng"] as? String,
let latitude = Double(latStr), let latitude = Double(latStr),
let longitude = Double(lngStr) else { let longitude = Double(lngStr) else {
print("[GetCurrentLocationHandler] 位置数据格式错误") print("[GetCurrentLocationHandler] 位置数据格式错误")
@ -491,6 +492,7 @@ private class GetCurrentLocationHandler: FunctionHandler {
"data": [ "data": [
"latitude": latitude, "latitude": latitude,
"longitude": longitude, "longitude": longitude,
"location": "\(latitude),\(longitude)",
"timestamp": Date().timeIntervalSince1970 * 1000 "timestamp": Date().timeIntervalSince1970 * 1000
] ]
] ]

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

2
pubspec.yaml

@ -1,7 +1,7 @@
name: voitrans name: voitrans
description: "Voitrans - AI Voice Assistant." description: "Voitrans - AI Voice Assistant."
publish_to: "none" publish_to: "none"
version: 1.0.6+20 version: 1.0.7+20
environment: environment:
sdk: ">=3.3.0 <4.0.0" sdk: ">=3.3.0 <4.0.0"

Loading…
Cancel
Save