iOS Swift后台位置监控

xmq68pz9  于 12个月前  发布在  Swift
关注(0)|答案(5)|浏览(124)

我写了一个应用程序与后台定位支持。该应用程序需要跟踪用户的位置点,因为他们通过城镇的送货路线。
我使用CLLocationManager中的startUpdatingLocation(),一切正常,直到应用程序在后台运行了大约15分钟。
然后,应用程序似乎终止,跟踪结束。
我知道这种持续的跟踪(即MapMyRun)必须工作,但我对如何工作感到困惑。
编辑:LocationManager配置如下

self.locationManager?.desiredAccuracy = kCLLocationAccuracyBestForNavigation
self.locationManager?.distanceFilter = kCLDistanceFilterNone
self.locationManager?.allowsBackgroundLocationUpdates = true
self.locationManager?.pausesLocationUpdatesAutomatically = false
self.locationManager?.activityType = CLActivityType.automotiveNavigation
self.locationManager?.showsBackgroundLocationIndicator = true

字符串

cnjp1d6j

cnjp1d6j1#

为了使位置更新在后台工作,您需要为应用启用后台模式功能。
如果你不这样做,应用程序将在操作系统认为合适的X时间后在后台终止。
点击你的目标,进入功能选项卡,启用后台模式,勾选位置更新。
x1c 0d1x的数据
尝试一下,如果它仍然不工作,我建议你上传你的位置管理器代码的地方看看。
希望能帮上忙!

dsekswqp

dsekswqp2#

iOS在后台杀死位置服务。您需要在iPhone设置中手动设置。

要启用访问,请点击设置>位置并选择始终

您可以显示警报通知用户并转到设置。

func checkUsersLocationServicesAuthorization(){
        /// Check if user has authorized Total Plus to use Location Services
        if CLLocationManager.locationServicesEnabled() {
            switch CLLocationManager.authorizationStatus() {
            case .notDetermined:
                // Request when-in-use authorization initially
                // This is the first and the ONLY time you will be able to ask the user for permission
                self.locationManager.delegate = self
                locationManager.requestWhenInUseAuthorization()
                break

            case .restricted, .denied:
                // Disable location features
                let alert = UIAlertController(title: "Allow Location Access", message: "MyApp needs access to your location. Turn on Location Services in your device settings.", preferredStyle: UIAlertController.Style.alert)

                // Button to Open Settings
                alert.addAction(UIAlertAction(title: "Settings", style: UIAlertAction.Style.default, handler: { action in
                    guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
                        return
                    }
                    if UIApplication.shared.canOpenURL(settingsUrl) {
                        UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
                            print("Settings opened: \(success)")
                        })
                    }
                }))
                alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil))
                self.present(alert, animated: true, completion: nil)

                break

            case .authorizedWhenInUse, .authorizedAlways:
                // Enable features that require location services here.
                let alert = UIAlertController(title: "Allow Location Access", message: "Lookout does not have access to your location while in the background. To enable access, tap Settings > Location and select Always", preferredStyle: UIAlertController.Style.alert)

                // Button to Open Settings
                alert.addAction(UIAlertAction(title: "Settings", style: UIAlertAction.Style.default, handler: { action in
                    guard let settingsUrl = URL(string: UIApplication.openSettingsURLString) else {
                        return
                    }
                    if UIApplication.shared.canOpenURL(settingsUrl) {
                        UIApplication.shared.open(settingsUrl, completionHandler: { (success) in
                            print("Settings opened: \(success)")
                        })
                    }
                }))
                alert.addAction(UIAlertAction(title: "Not Now", style: UIAlertAction.Style.default, handler: nil))
                self.present(alert, animated: true, completion: nil)

                break
            }
        }
    }

字符串
为了更准确,也调用此方法

func startLocationService(){
    locationManager.startUpdatingLocation()
    locationManager.startMonitoringSignificantLocationChanges()
    locationManager.pausesLocationUpdatesAutomatically = false
    locationManager.allowsBackgroundLocationUpdates = true
    locationManager.showsBackgroundLocationIndicator = true
}


不要忘记在目标->签名和功能中启用后台模式
最后一项检查是在info.plist中添加权限
这就是所有你必须做的现场位置在后台

webghufk

webghufk3#

您的应用在后台获取的位置更新完全由iOS处理,不受您的应用控制。
根据苹果关于后台定位服务的文档:
启用此模式不会阻止系统挂起应用程序,但它会告诉系统,每当有新的位置数据要传递时,它应该唤醒应用程序。因此,此键有效地让应用程序在后台运行,以便在位置更新发生时处理位置更新。
有关详细信息,请参阅Background Execution

0aydgbwb

0aydgbwb4#

我正在构建一个徒步旅行应用程序,其中包括徒步记录功能,所以需要访问详细的用户位置,而应用程序在后台很长一段时间。我遇到了与OP相同的问题,经过几周的挣扎,我想我已经解决了这个问题,并希望分享我所学到的,希望能帮助别人。
这与Strava和AllTrails等应用程序的功能非常相似,所以我知道这是可能的,但我遇到了与OP相同的问题。位置更新会收到一段时间-从几分钟到几个小时不等-然后关闭。当我重新打开应用程序时,它会重新启动,但当然,在停机期间,我会丢失所有用户的位置。
(By这里的“background”,我的意思是应用程序没有显示在屏幕上,而是用户没有完全关闭它。
首先,我将列出一些通常给出的建议,这些建议要么不起作用,要么只起部分作用:
1.在应用程序后台功能中启用“位置更新”,并将locationManager.allowBackgroundLocationUpdates设置为true -这是必要的,但还不够,以维护后台位置更新!确实,您必须这样做才能使后台位置更新工作,但设置这并不能防止它们被任意关闭。
1.设置locationManager.showsBackgroundLocationIndcator、.activityType、.desiredAccuracy、.pausesLocationUpdatesAutomatically -据我所知,这些对是否维护后台位置没有影响
1.获得“始终”授权-尽管一些著名的和受人尊敬的教程会告诉你,这是不需要的后台位置更新-“在使用时”授权就足够了。
获得“总是”授权实际上允许您的应用在重大位置更改时从完全关闭状态唤醒,这是一个非常不同的用例。(如果你不相信我,请考虑Strava没有获得“总是”权限,它工作得很好。=)
经过大量的实验,我推断如果你的应用程序处理太多或使用太多内存或这些情况的组合,iOS会关闭你的位置更新。我能够让位置无限期地更新(据我所知,到目前为止),当应用程序进入后台时,关闭几乎所有的东西,并确保位置更新触发的处理量非常小。
这意味着当我的应用在后台时,唯一做任何工作的是一个非常轻量级的CLLocationManagerDelegate(称为LocationRecorder)。这个对象所做的就是接收lat/lon更新并将它们存储在数组中,以便当应用返回前台时它们可用。
需要考虑的事项:

  • 我没有在后台创建CoreData对象,LocationRecorder只是接收CLLocation点,并将它们存储在一个非常简单的对象数组中(它们只有lat、lon、time和sequence number字段)。
  • 我不得不关闭任何其他CLLocationManagerDelegates。例如,我有一个视图模型,它接收位置更新并维护用户附近的公园和Map列表。当应用进入后台时,它会关闭。
  • 由于我不明白的原因,iOS似乎在应用程序处于后台时一直在进行视图更新。如果您的位置更新触发视图更新,这将导致位置更新关闭。由于我在Map上显示用户的路线,当然位置更新触发视图更新!

我通过创建“LocationGateway”可观察对象来解决这个问题。这些网关监听我一直运行的LocationRecorder上的更新,并将它们发布给视图使用。(我还将任何特定于视图的操作或过滤放在这些类中。)当应用转到后台时,我关闭这些。
这是它的基本结构:

class LocationRecorderGateway : ObservableObject {

    @Published var waypoints = [LocationRecorder.WaypointLocation]()

    private var receiver: AnyCancellable? = nil

    private let locationRecorder = LocationRecorder.shared()

    // start() and stop() should be called when the app goes to background/comes back
    // to foreground
    func start() {
    
        // Do one initial updates when the app wakes up, then set up listener for
        // future updates.
        self.updateWaypoints()
    
        receiver = locationRecorder.$waypoints.sink { [weak self] waypoints in
            if let self {
                self.updateWaypoints()
            }
        }
    }

    func stop() {
        receiver?.cancel()
    }

    private let updatingWaypoints = NSLock()

    func updateWaypoints() {
    
        // Do any processing needed here. You might also consider keeping track of how many
        // waypoints you already processed and only process "new" ones instead of injesting
        // the entire list every time

        // If this method is long-running, you may want to run it asynchronously. If so, and
        // you're using any state variables, you may need to use an NSLock().
        waypoints = self.locationRecorder.waypoints
    
   }
}

字符串
再一次,我分享了什么为我工作,以解决OP的问题.然而,我会注意到,我绝对不是一个Maven在这里,真的很想有人从苹果或更有知识的用户纠正任何这一点,并提供任何更容易的方法来实现这一点.

cigdeys3

cigdeys35#

看看

CLLocationManager.startMonitoringSignificantLocationChanges()

字符串
The Apple documentation here

相关问题