Files
suixinkan_uikit/suixinkan/Features/Location/LocationProvider.swift
汉秋 5eef31b8da 完善景区排队设置页与全局按钮配置迁移。
重构排队设置与变更日志交互,补充 Overlay 与资源,并将多页面主操作按钮统一到 UIButton Configuration,同步更新相关单元测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-14 16:51:23 +08:00

113 lines
4.0 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// LocationProvider.swift
// suixinkan
//
import CoreLocation
import Foundation
/// `AMapLocationManager` Android `LocationProvider`
@MainActor
final class LocationProvider: NSObject, LocationProviding {
nonisolated static let shared = LocationProvider()
private let permissionManager = CLLocationManager()
private let geocoder = LocationGeocoder.shared
nonisolated override init() {
super.init()
}
@MainActor
func requestSnapshot(desiredAccuracy: CLLocationAccuracy = kCLLocationAccuracyBest) async throws -> HomeLocationSnapshot {
try AMapBootstrap.requireConfigured()
try await ensureLocationPermission()
let manager = makeLocationManager(
desiredAccuracy: desiredAccuracy,
locatingWithReGeocode: true
)
return try await withCheckedThrowingContinuation { continuation in
let started = manager.requestLocation(withReGeocode: true) { location, regeocode, error in
if let error {
continuation.resume(throwing: error)
return
}
guard let location else {
continuation.resume(throwing: LocationProviderError.locationFailed)
return
}
let address = regeocode?.formattedAddress ?? ""
continuation.resume(returning: HomeLocationSnapshot(
latitude: location.coordinate.latitude,
longitude: location.coordinate.longitude,
address: address
))
}
if !started {
continuation.resume(throwing: LocationProviderError.locationFailed)
}
}
}
@MainActor
func requestCoordinate(desiredAccuracy: CLLocationAccuracy) async throws -> CLLocationCoordinate2D {
try AMapBootstrap.requireConfigured()
try await ensureLocationPermission()
let manager = makeLocationManager(
desiredAccuracy: desiredAccuracy,
locatingWithReGeocode: false
)
return try await withCheckedThrowingContinuation { continuation in
let started = manager.requestLocation(withReGeocode: false) { location, _, error in
if let error {
continuation.resume(throwing: error)
return
}
guard let location else {
continuation.resume(throwing: LocationProviderError.locationFailed)
return
}
continuation.resume(returning: location.coordinate)
}
if !started {
continuation.resume(throwing: LocationProviderError.locationFailed)
}
}
}
@MainActor
func reverseGeocode(latitude: Double, longitude: Double) async -> String {
await geocoder.reverseGeocode(latitude: latitude, longitude: longitude)
}
///
func ensureLocationPermission() async throws {
permissionManager.desiredAccuracy = kCLLocationAccuracyBest
let initialStatus = permissionManager.authorizationStatus
if initialStatus == .notDetermined {
permissionManager.requestWhenInUseAuthorization()
try await Task.sleep(nanoseconds: 500_000_000)
}
let status = permissionManager.authorizationStatus
guard status == .authorizedWhenInUse || status == .authorizedAlways else {
throw LocationProviderError.permissionDenied
}
}
private func makeLocationManager(
desiredAccuracy: CLLocationAccuracy,
locatingWithReGeocode: Bool
) -> AMapLocationManager {
let manager = AMapLocationManager()
manager.desiredAccuracy = desiredAccuracy
manager.locationTimeout = 30
manager.reGeocodeTimeout = 10
manager.locatingWithReGeocode = locatingWithReGeocode
return manager
}
}