当应用程序未运行(终止/终止)时,如何保持核心位置和核心蓝牙运行?

Posted

技术标签:

【中文标题】当应用程序未运行(终止/终止)时,如何保持核心位置和核心蓝牙运行?【英文标题】:How to keep Core Location and Core Bluetooth running when app is not running (killed/ terminated)? 【发布时间】:2017-07-26 04:43:19 【问题描述】:

如果我终止应用程序,我在尝试保持我的功能运行时卡住了。

是否可以在应用未运行时保持核心位置(地理围栏/地理定位)和核心蓝牙运行?如果可能的话如何解决我的问题?我已经检查了后台模式,并实现了核心定位方法。 这是我的代码:

    class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate 

        var viewController = ViewController()
        var window: UIWindow?

        var locationManager = CLLocationManager()

        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 

            locationManager = CLLocationManager()
            locationManager.requestAlwaysAuthorization()

            locationManager.delegate = self
            locationManager.distanceFilter = kCLDistanceFilterNone
            locationManager.desiredAccuracy = kCLLocationAccuracyBest

            locationManager.pausesLocationUpdatesAutomatically = false

            if #available(ios 9.0, *) 
                locationManager.allowsBackgroundLocationUpdates = true
            

            beaconRegion.notifyEntryStateOnDisplay = true
            beaconRegion.notifyOnEntry = true
            beaconRegion.notifyOnExit = true

            locationManager.startMonitoring(for: beaconRegion)
            locationManager.stopRangingBeacons(in: beaconRegion)
            locationManager.startRangingBeacons(in: beaconRegion)
            locationManager.startUpdatingLocation()

            return true
        

        func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) 
            if (region.identifier == beaconRegionIdentifier) 
                manager.requestState(for: region)
                goBackground()
            
        

        func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) 
            print("you exited region")
        

        func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) 
            if (region.identifier == beaconRegionIdentifier) 
                manager.stopUpdatingLocation()

                switch state 
                case .inside:
                    manager.startRangingBeacons(in: region as! CLBeaconRegion)
                    manager.startUpdatingLocation()
                case .outside:
                    let delay = DispatchTime.now() + .seconds(3)
                    DispatchQueue.main.asyncAfter(deadline: delay) 
                        manager.requestState(for: region)
                    
                case .unknown:
                    let delay = DispatchTime.now() + .seconds(3)
                    DispatchQueue.main.asyncAfter(deadline: delay) 
                        manager.requestState(for: region)
                    
                
            
        

        func locationManager(_ manager: CLLocationManager, didRangeBeacons beacons: [CLBeacon], in region: CLBeaconRegion) 

            let state = UIApplication.shared.applicationState
            switch(state)
            case.active,
                .inactive,
                .background:

                let mainView = UserDefaults.standard.bool(forKey: "toMainView")

                var isWakeUpRunning = UserDefaults.standard.bool(forKey: "isWakeUpRunning")

                if isWakeUpRunning 
                    if mainView 
                        for aBeacon in beacons
                            if aBeacon.rssi > WAKE_UP_THRESHOLD   && aBeacon.rssi != 0
                                UserDefaults.standard.set(false, forKey: "isWakeUpRunning")
                                self.viewController.startFunction()
                                manager.stopRangingBeacons(in: region)
                            else if aBeacon.rssi != 0 && aBeacon.rssi < WAKE_UP_THRESHOLD 
                                manager.stopRangingBeacons(in: region)
                                manager.requestState(for: region)
                            
                        
                    
                else
                    manager.stopRangingBeacons(in: region)
                    manager.requestState(for: region)
                
            
          

 func goBackground() 
        let app = UIApplication.shared
        var bgTask: UIBackgroundTaskIdentifier = 0
        bgTask = app.beginBackgroundTask(expirationHandler: 
            NSLog("Expired: %lu", bgTask)
            app.endBackgroundTask(bgTask)
        )
        NSLog("Background: %lu", bgTask)


    

根据我的代码,它可以在前台和后台运行。但是当我从任务切换器向上滑动应用程序时,它无法工作。而且我也无法从 xcode 中看到日志。有什么想法可以帮助我吗?

【问题讨论】:

你需要使用 startMonitoringRegion 已经实现 【参考方案1】:

一旦您从任务切换器向上滑动应用程序,您的应用程序将被终止,但 CoreLocation 仍将在操作系统级别为您工作,寻找与您所在地区匹配的信标:

locationManager.startMonitoring(for: beaconRegion)

一旦该区域发生变化(didEnter 或 didExit),您的应用将重新启动到后台。此时将依次调用以下方法:

    application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?)

    locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion)

届时您的应用将继续在后台运行。因为您的应用会启动一个后台任务,所以这会持续 180 秒,然后才会暂停。

但是,您的应用不会在从屏幕滑出到下一次区域转换发生之间运行。这是您能做的最好的事情。

【讨论】:

如果我的应用程序是通过退出一个区域启动的(在它被终止之后),我会在里面做locationManager.startUpdatingLocation,而我在后台模式下启用了位置......会我的位置工作 180 或无限期? 2. 如果应用程序在后台或暂停中保持活动状态,但由于某种原因我的位置跟踪被操作系统暂停(即没有被我暂停),我是否能够无限期恢复位置跟踪或再次 180 秒? (1) 你的位置会在区域进入/退出时再次开始更新,如果你成功获得了后台运行的权限,它将无限期地继续运行,就像应用程序从未被杀死一样. (2) 我不确定您如何建议暂停跟踪。例如,如果用户关闭了位置信息,那么不,您的应用将无法恢复跟踪,直到用户重新打开位置信息。 locationManagerDidPauseLocationUpdates回调暂停 根据文档here,该方法在位置不变时被调用。之后,您的应用可能会再次调用 locationManager.startUpdatingLocation。我认为这与您是否在后台无关。

以上是关于当应用程序未运行(终止/终止)时,如何保持核心位置和核心蓝牙运行?的主要内容,如果未能解决你的问题,请参考以下文章

应用程序被终止时未收到推送通知 - iOS

iOS App终止时如何继续扫描BLE传感器并识别传感器keyEvent

由于运行应用程序时未捕获的异常而终止应用程序

在运行和终止时处理 FCM 通知

如何避免我的应用程序在后台运行并跟踪我的位置时被终止?

保持程序终止后的硬件句柄