如何使用SwiftUI获取当前位置?

13

尝试使用SwiftUI获取当前位置。以下代码,无法使用didUpdateLocations代理进行初始化。

class GetLocation : BindableObject {
    var didChange = PassthroughSubject<GetLocation,Never>()

    var location : CLLocation {
        didSet {
            didChange.send(self)
        }
    }
    init() {}
}

为什么你无法在这个类中创建CLLocationManager? - DenFav
3个回答

8
下面的代码可以运行(不适合生产环境)。实现CLLocationManagerDelegate工作良好,并相应地更新lastKnownLocation
别忘了在您的Info.plist中设置NSLocationWhenInUseUsageDescription
class LocationManager: NSObject, ObservableObject, CLLocationManagerDelegate {
    private let manager = CLLocationManager()
    var lastKnownLocation: CLLocation?

    func startUpdating() {
        manager.delegate = self
        manager.requestWhenInUseAuthorization()
        manager.startUpdatingLocation()
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        print(locations)
        lastKnownLocation = locations.last
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        if status == .authorizedWhenInUse {
            manager.startUpdatingLocation()
        }
    }
}

2
对于任何遇到错误:“使用未解决的标识符'PassthroughSubject'”,请确保在文件顶部添加“import Combine”。 - Charlie Hill
这段代码为什么不适合投入生产环境?我猜拒绝位置权限的处理是一个原因? - undefined

5
我已经为https://github.com/himbeles/LocationProvider编写了一个单文件的Swift软件包,并提供了使用说明。它提供了一个ObservableObject类型的封装类,用于CLLocationManager及其委托。其中有一个@Published属性location,可以直接在SwiftUI中使用,以及一个名为locationWillChangePassthroughSubject<CLLocation, Never>,您可以通过Combine进行订阅。两者都会在每个CLLocationManagerdidUpdateLocations事件上更新。
此外,它还处理了先前拒绝位置访问的情况:默认行为是向用户呈现请求在应用程序设置中启用访问权限的提示和转到该位置的链接。
在SwiftUI(>iOS 14,>macOS 11)中的使用方法:
import SwiftUI
import LocationProvider

struct ContentView: View {
    @StateObject var locationProvider = LocationProvider()
    
    var body: some View {
        VStack{
            Text("latitude \(locationProvider.location?.coordinate.latitude ?? 0)")
            Text("longitude \(locationProvider.location?.coordinate.longitude ?? 0)")
        }
        .onAppear {
            do {try locationProvider.start()} 
            catch {
                print("No location access.")
                locationProvider.requestAuthorization()
            }
        }
    }
}

这在我的iOS 14上不起作用,应用程序崩溃并显示以下错误=>“无效参数不满足:!stayUp || CLClientIsBackgroundable(internal-> fClient)”。 - Ahmadreza
1
@Ahmadreza 看起来,后台权限可能存在问题?您是否按照包的 README.md 中所述将 Location 添加到 UIBackgroundModes 中?我已经使用 Xcode 12 beta 6 设置了一个最小的 SwiftUI 示例,并且在设备和模拟器上都按预期运行。请参见 https://github.com/himbeles/LocationProviderExample - lsrggr
@ lsrggr,不,我没有,那一定是原因,谢谢你,但我还是用了“Paul Hutson”的方法来定位。 - Ahmadreza

3

从 Xcode 11 Beta 4 开始,您需要将 didChange 改为 willChange

var willChange = PassthroughSubject<LocationManager, Never>()

var lastKnownLocation: CLLocation? {
    willSet {
        willChange.send(self)
    }
}

2
此外,在Xcode11.1上,您需要将BindableObject更改为ObservableObject- - ecolell
我还需要在 lastKnownLocation 声明前加上 @Published (XCode 12.0)。 - Jason Campbell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接