0

Hi I'm making an app that sends POST location update requests to a web application. I have one function called locationUpdate that I'd like to call intermittently once the app is in the background however I have't found a way to do it yet.

I have all the basics like Allow Location Always set. The app currently makes one HTTP POST request right when it enters the background because of this code in the AppDelegate file:

 func applicationDidEnterBackground(_ application: UIApplication) {

    sendLocation.determineCurrentLocation()
}

I also have this in the AppDelegate because I've seen it in a few stack overflow answers:

 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplicationBackgroundFetchIntervalMinimum)
    return true
}

So all this but the app doesn't call sendLocation.determineCurrentLocation() (The function that makes the POST request) more than once and that is when the app is closed.

Can anyone tell me how to implement intermittent calling of the sendLocation function?

EDITED to show my locationManager:

 func determineCurrentLocation(){

    locationManager.delegate = self
    locationManager.allowsBackgroundLocationUpdates=true
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()


    if CLLocationManager.locationServicesEnabled(){
        DispatchQueue.main.async {

            self.locationManager.requestLocation()
        }

    }
    else if (!CLLocationManager.locationServicesEnabled())
    {
        print("You need to enable location services to use this app")

    }




}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
    locationManager.stopUpdatingLocation()
    userLocation = locations[0] as CLLocation
    locationStruct.latitude=userLocation?.coordinate.latitude
    locationStruct.longitude=userLocation?.coordinate.longitude



    print(userLocation?.coordinate.latitude)
    print(userLocation?.coordinate.longitude)

    sendLocationPost()


}
madmanprogram
  • 51
  • 1
  • 7
  • You will need to perform the post in `didUpdateLocations` – Paulw11 Mar 08 '18 at 00:07
  • @Paulw11 Can you elaborate what you mean? When I call sendLocation.determineCurrentLocation() , that function calls didUpdateLocations() – madmanprogram Mar 08 '18 at 00:20
  • You need to get background location permission, turn on significant location updates and call `startUpdatingLocation` with background updates enabled on your location manager. You will then get calls to `didUpdateLocations` in the background. You need to consider carefully the accuracy you are requesting since frequent high accuracy location updates will significantly impact battery life. – Paulw11 Mar 08 '18 at 00:22
  • @Paulw11 I edited my answer to include my location manager because I think I've done everything you've mentioned but it still doesn't work. Are you saying that at my AppDelegates current state it should be updating at regular intervals? Because I can't see how it would already be doing that unless I were to add something to the AppDelegate itself. – madmanprogram Mar 08 '18 at 00:35
  • You need to call `startUpdatingLocation` not `requestLocation` - `requestLocation` only gives a one-time update. `startUpdatingLocation` will give continual updates. You will probably want to put some code in `didUpdateLocations` to only update your server every few minutes as the settings you have will deliver location updates once per second if the user is moving – Paulw11 Mar 08 '18 at 00:37
  • This would be a nasty intimacy violation - basically your app will know every location I go to. Not something I'd want to have installed on my iPhone. – Cristik Mar 08 '18 at 07:22
  • @Cristik It's a location sharing app, it only sends location to be displayed on a map when the user specifies they want to. – madmanprogram Mar 08 '18 at 11:54

1 Answers1

0

You won't be able to do what you are trying to do unless you set up your app as a turn-by-turn navigation app and ask for permission to get location updates in the background.

Apps only get a very short time in the background before they are suspended.

You can ask for more background time with the beginBackgroundTask(expirationHandler:) call, but that's normally limited to 3 minutes of background time at max. (Search on that method to find the docs about it.)

Only certain types of apps are allowed to run indefinitely in the background. (Turn-by-turn navigation apps and streaming music apps.) You have to set up your info.plist to declare that your app is one of those types of apps. That is documented in the iOS docs that come with Xcode.

EDIT:

As Paul points out in his comment, you CAN ask for "always" location update permission and then ask for significant location change updates, although those are rather crude and you can't control the time interval between location updates (and won't get any updates until the OS decides the user has moved a significant distance.)

Community
  • 1
  • 1
Duncan C
  • 128,072
  • 22
  • 173
  • 272
  • You don't need to be a turn-by-turn navigation app; you simply need "always" location permission and to have background locations enabled in conjunction with significant location updates. This can impact battery life so judicious selection of accuracy settings is required. – Paulw11 Mar 08 '18 at 00:24
  • significant location updates gives you fairly crude granularity on your location updates, and you won't get ANY updates unless you move enough to trigger an update. – Duncan C Mar 08 '18 at 00:57
  • You have to combine both; If you only use `startUpdatingLocation` the background updates stop after a few minutes. If you use both significant location updates *and* `startUpdatingLocation` then you will get background updates with high accuracy indefinitely – Paulw11 Mar 08 '18 at 01:00
  • Really? If that's true, that's a very cool trick, and one I bet Apple does not intend to work that way. – Duncan C Mar 08 '18 at 01:09
  • Paul, It sounds like you should post your solution as your own answer, since you seem to have a complete solution. – Duncan C Mar 08 '18 at 01:10
  • Not sure if that is what is intended, but it works, at least it did. I researched the problem for a client a few years ago. I haven't tested it in iOS 11. I think I actually found the answer here; let me see if I can dig up that answer. – Paulw11 Mar 08 '18 at 01:11
  • Here it is -https://stackoverflow.com/questions/20187700/startupdatelocations-in-background-didupdatingtolocation-only-called-10-20-time – Paulw11 Mar 08 '18 at 01:14