Files
suixinkan_uikit/suixinkan/Features/Home/Services/HomeLocationProvider.swift

98 lines
3.1 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.

//
// HomeLocationProvider.swift
// suixinkan
//
import CoreLocation
///
struct HomeLocationSnapshot: Sendable {
let latitude: Double
let longitude: Double
let address: String
}
/// CoreLocation
final class HomeLocationProvider: NSObject, CLLocationManagerDelegate {
private let manager = CLLocationManager()
private var coordinateContinuation: CheckedContinuation<CLLocationCoordinate2D, Error>?
override init() {
super.init()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
}
///
func requestSnapshot() async throws -> HomeLocationSnapshot {
let status = manager.authorizationStatus
if status == .notDetermined {
manager.requestWhenInUseAuthorization()
try await Task.sleep(nanoseconds: 300_000_000)
}
let resolvedStatus = manager.authorizationStatus
guard resolvedStatus == .authorizedWhenInUse || resolvedStatus == .authorizedAlways else {
throw HomeLocationProviderError.permissionDenied
}
let coordinate = try await requestCoordinate()
let address = await reverseGeocode(latitude: coordinate.latitude, longitude: coordinate.longitude)
return HomeLocationSnapshot(
latitude: coordinate.latitude,
longitude: coordinate.longitude,
address: address
)
}
private func requestCoordinate() async throws -> CLLocationCoordinate2D {
try await withCheckedThrowingContinuation { continuation in
self.coordinateContinuation = continuation
manager.requestLocation()
}
}
private func reverseGeocode(latitude: Double, longitude: Double) async -> String {
let location = CLLocation(latitude: latitude, longitude: longitude)
let geocoder = CLGeocoder()
do {
let placemarks = try await geocoder.reverseGeocodeLocation(location)
return placemarks.first?.formattedAddress ?? ""
} catch {
return ""
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
coordinateContinuation?.resume(returning: location.coordinate)
coordinateContinuation = nil
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
coordinateContinuation?.resume(throwing: error)
coordinateContinuation = nil
}
}
///
enum HomeLocationProviderError: LocalizedError {
case permissionDenied
var errorDescription: String? {
switch self {
case .permissionDenied: "需要位置权限才能上线"
}
}
}
private extension CLPlacemark {
var formattedAddress: String {
[subLocality, locality, administrativeArea]
.compactMap { $0?.trimmingCharacters(in: .whitespacesAndNewlines) }
.filter { !$0.isEmpty }
.joined(separator: "")
}
}