How to get periodicaly new location when app is in background or killed
Asked Answered
E

1

6

I want to get new location every 1min when my app is in background or killed. Here is my code :

Location Service:

class LocationService: NSObject, CLLocationManagerDelegate {

    static let shared = LocationService()
    var locationManager = CLLocationManager()
    var significatLocationManager = CLLocationManager()
    var currentLocation: CLLocation!
    var timer = Timer()
    var bgTask = UIBackgroundTaskInvalid

    func startUpdatingLocation() {
        locationManager.requestAlwaysAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.distanceFilter = kCLDistanceFilterNone
        if #available(iOS 9.0, *) {
            locationManager.allowsBackgroundLocationUpdates = true
        }
        locationManager.delegate = self
        locationManager.startUpdatingLocation()
    }

    func stopUpdatingLocation() {
        locationManager.stopUpdatingLocation()
        timer.invalidate()
    }

    func restartUpdatingLocation() {
        locationManager.stopMonitoringSignificantLocationChanges()
        timer.invalidate()
        startUpdatingLocation()
    }

    func startMonitoringLocation() {
        locationManager.stopUpdatingLocation()
        locationManager.startMonitoringSignificantLocationChanges()
        timer.invalidate()
    }

    func changeLocationAccuracy(){
        switch locationManager.desiredAccuracy {
        case kCLLocationAccuracyBest:
            locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
            locationManager.distanceFilter = 99999
        case kCLLocationAccuracyThreeKilometers:
            locationManager.desiredAccuracy = kCLLocationAccuracyBest
            locationManager.distanceFilter = kCLDistanceFilterNone
        default: break
        }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        bgTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
            UIApplication.shared.endBackgroundTask(self.bgTask)
            self.bgTask = UIBackgroundTaskInvalid
        })

        currentLocation = locations.last!

        let interval = currentLocation.timestamp.timeIntervalSinceNow
        let accuracy = self.locationManager.desiredAccuracy

        if abs(interval) < 60 && accuracy != kCLLocationAccuracyThreeKilometers {        
            timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(LocationService.changeLocationAccuracy), userInfo: nil, repeats: false)
            changeLocationAccuracy()
        }
    } 
}

App delegate:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
     if launchOptions?[UIApplicationLaunchOptionsKey.location] != nil {
          LocationService.shared.restartUpdatingLocation()
     }
}

func applicationDidEnterBackground(_ application: UIApplication) {
     LocationService.shared.restartUpdatingLocation()
}

func applicationWillTerminate(_ application: UIApplication) {
     LocationService.shared.startMonitoringLocation()
}

View controller:

override func viewDidLoad() {
    LocationService.shared.startUpdatingLocation()
}

But my code is not working, i'm not getting new location after a few minutes when my app is in background. and same when my app is suspended or killed. Is there any solution for that ? please not that i'm using Swift 3 & xcode 8.1.

Thank's in advance

Embellish answered 7/1, 2017 at 18:23 Comment(3)
You have to move far to get SignificantLocationChanges. At least >500 meters.Orren
This is when my app is killed. but how i can get indefinitely location update in background each 1min ?Embellish
You can't. You can try to misuse backgroundFetch.Orren
C
4
  • If you call startUpdatingLocation when your app is already in the background, then you will only receive location updates for a few minutes.

  • If you call startUpdatingLocation while your app is in the foreground and then your app moves to the background, you will continue to receive location updates indefinitely.

  • If you call startMonitoringSignificantLocationChanges in the foreground and leave it enabled then you can call startUpdatingLocation in the background and receive updates indefinitely.

  • If the user terminates your app (by swiping up in the app switcher) then you will no longer receive location updates until the user re-launches your app.

Since your code stops and starts location monitoring when it moves to the background of only get location updates for a few minutes. If you start location monitoring foreground and do nothing when the app moves to the background then you will continue to receive location updates.

Consign answered 7/1, 2017 at 20:20 Comment(5)
Can you tell me please what should i change in my code above ?Embellish
You need to add a call to startMonitoringSignificantLocationChanges where you create your location manager and make sure that this is called from the foreground. You can also remove the code from applicationWillTerminate as that serves no purpose.Consign
But SignificantLocation give new location only if device move more than 500m. i don't want that i need location every 1minEmbellish
You can't get it every minute, you will get an update when the location changes, this may be quicker than every minute if the device is moving and less than one minute if it is stationary. The trick is, however, that if significant location monitoring is enabled in the foreground and remains enabled then you can start/stop more accurate location monitoring from the background without the time limits. You can also simply start accurate location monitoring in the foreground and leave it running, ut it uses more battery. Your problem is you restart monitoring when you move to the backgroundConsign
You already have the right code. Just don't call stopUpdatingLocation when you are in the backgroundConsign

© 2022 - 2024 — McMap. All rights reserved.