Forum Xamarin.iOS

CLLocationManager, RequestUpdates stops triggering update callback.

patcarutherspatcaruthers USMember ✭✭✭

What would make background location updates stop happening?

I am using RequestLocation because i only need to know the device location occasionally,
in order to respond a specific background (silent) notification from my server. i do not need
to be constantly updated about the device location.

It works for a while and then stops getting the update event after a RequestLocation.
(well, one time it responded 7 minutes after i made the request.)

During testing RequestLocation could be called several times in a minute - is that frequent
enough to cause issues?

I tried using StartUpdatingLocation instead (with a stop immediately after i got the update event)
but that didn't help -- but perhaps the OS was already ignoring my requests by then...

I have logging for the Failed and LocationUpdatesPaused events and they do not appear
to be happening, so i'm clueless about what's happening.

Tagged:

Best Answer

  • patcarutherspatcaruthers USMember ✭✭✭
    Accepted Answer

    the last update on this; really.
    After i posted the above i discovered that "it worked" was "only sort of" - i got exactly 2 updates if the app was in the background when i called StartUpdatingLocations. And 2 updates are not enough for the system to get a good fix - the first update is usually just what you got the last time you asked and the second may not be much better. You need to get several - 6 or more, before you can trust the answer.

    But i found this post and the long and very information answer by g. malde is great and his suggestion of using BeginBackgroundTask works. It allows me to get updates for at least 20 seconds, which is enough.

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    If you do not want the LocationsUpdated event to be called too often. Reducing the CLLocationManager's DesiredAccuracy and adding the StopUpdatingLocation method after you get the correct locations will be a trick.
    But from your description, I think the issue is you called the RequestLocation several times in a minute.
    According to this documentation: https://developer.apple.com/documentation/corelocation/cllocationmanager/1620548-requestlocation

    This method returns immediately. Calling it causes the location manager to obtain a location fix (which may take several seconds) and call the delegate’s locationManager(_:didUpdateLocations:) method with the result.

    It means once you called RequestLocation, it will trigger LocationsUpdated delegate. So why do you want

    RequestLocation could be called several times in a minute

    You can store the location and the request time the first time you want to get the location. Then each time you need to know the location, check the storage. If you think the time is not out of date, use the stored location instead of requesting a new location. You just need to use RequestLocation to request a new location when you find the request time is out of date. This will reduce the numbers of LocationsUpdated's triggering.

  • patcarutherspatcaruthers USMember ✭✭✭

    Yes, my suspicion was that the multiple calls got the app blocked.
    In real life the request will be rare - not even once a week, but i failed to consider what happens during development and testing. oops.

    Using a cached value if it is not too stale was my plan.
    hopefully my phone will talk to me again!

  • LandLuLandLu Member, Xamarin Team Xamurai

    Yes for developing what we can do is reducing the frequent usage of RequestLocation and add the StopUpdatingLocation in the LocationsUpdated event:

    public override void LocationsUpdated(CLLocationManager manager, CLLocation[] locations)
    {
        CLLocation location = locations.FirstOrDefault();
    
        var latitude = location.Coordinate.Latitude;
        var longitude = location.Coordinate.Longitude;
        Console.WriteLine("-----------" + latitude + "Longitude" + longitude);
    
        locationManager.StopUpdatingLocation();
    }
    

    Also set a lower accuracy is a choice: locationManager.DesiredAccuracy = CLLocation.AccuracyHundredMeters;

  • patcarutherspatcaruthers USMember ✭✭✭

    actually, this does not seem to have been the problem and i don't yet know what is wrong.

    it really looks like RequestLocation is not intended for use in the background at all. If i change my code to use StartUpdating instead i get the background updates on the same device that won't service RequestLocation.

  • LandLuLandLu Member, Xamarin Team Xamurai

    StartUpdatingLocation will monitor the location's changing and trigger the LocationsUpdated over and over again until we used StopUpdatingLocation to stop this monitoring. If you have enabled the background mode: Location updates, this operation will still move on in the background state.
    So what you really want to achieve in the background state and what you have tried?

  • patcarutherspatcaruthers USMember ✭✭✭

    Yes, i am aware of the difference.

    The goal is simple: when the application is running in the background it will receive a ping notification from the server and respond to that with its current location.

    I wanted to use RequestLocation specifically because i have no need to constantly monitor the device location,
    i just need to know where it is at the time i receive the ping.

    I have all the background modes enabled correctly - when i change the app to use monitoring instead of the one time request the update events happen regularly while in the background.

    I can, of course, use monitoring to always track the device location and simply use the last received location for my ping response, but it seems overkill when all i need is "where am i right now?".

    what i first implemented was:
    - receive the ping notification
    - call RequestLocation
    - receive the location update event and respond to the ping with the current location

    I have not gotten this to work.
    A call to RequestLocation when in the background seems to not trigger a location update event until the application is brought into the foreground. if this is by design then i cannot use RequestLocation because the app is almost always in the background. perhaps the time it takes is simply too long for what is allowed while handling a background notification.

    If i change this around to
    - StartUpdatingLocations (and get updates while in the background)
    - receive the ping notification
    - respond to the ping notification with the last reported location

    It works just fine -- the update events have been occurring while the app is in the background, and the last reported location is recent, etc.

    I can limit the distance filter so the updates don't happen very often, but in real usage this ping is going to happen less than once a week.

    My next attempt will be to
    - receive the ping notification
    - StartUpdatingLocations
    - receive the location update event and respond to the ping
    - StopUpdatingLocations

    But i wonder if calling StartUpdatingLocations while in the background will fail just as RequestLocation fails.

  • LandLuLandLu Member, Xamarin Team Xamurai

    If you are meaning the RequestLocation doesn't work when app is on the background state. Did you add this configuration:

    locationManager.PausesLocationUpdatesAutomatically = false;
    locationManager.AllowsBackgroundLocationUpdates = true;
    
  • patcarutherspatcaruthers USMember ✭✭✭

    Yes, that is what i am saying and Yes, i have those statements.

    (i do not think that StartUpdatingLocation would be working in the background if i had not)

  • LandLuLandLu Member, Xamarin Team Xamurai

    @patcaruthers Alright, then try the last workaround, if StartUpdatingLocation can work well on the background. It's the same thing and also can fit your requirement.

  • patcarutherspatcaruthers USMember ✭✭✭

    Yes, that is the plan.
    it does mean i will be getting updates that i do not care about, which is wasteful, but that is better than no updates.

  • LandLuLandLu Member, Xamarin Team Xamurai

    There's no need to start when app begins entering the background. As your last plan above. When the notification comes, start the location updating will be the trick. This will not receive too much useless location information.
    Moreover please make sure your silent notification has successfully triggered the DidReceiveRemoteNotification event. Because if app has been in the background state for a long time, it will be forced quit by system. And silent notification can only be received when app is on background or foreground state not killed.

  • patcarutherspatcaruthers USMember ✭✭✭

    I don't know how long a "long time" is for you statement: "If app has been in the background state for a long time, it will be forced quit by system. And silent notification can only be received when app is on background or foreground state not killed." Do you have a number for that?

    But whatever that number is, it is for 100% certain that issue is Not part of the problem, we are definitely receiving the ping from the server, my problem has been entirely about getting a current location.

  • LandLuLandLu Member, Xamarin Team Xamurai

    It's hard to give you the correct time that app can run in the background state. But if it doesn't have a task to run, the memory it takes will be recovered by system. If I remember correctly it was up to 10 minutes.
    This could be the reason. If app is still on the background, both StartUpdatingLocation and RequestLocation could get the current location.

  • patcarutherspatcaruthers USMember ✭✭✭

    Final results of testing of testing the options --

    Neither this plan:

    • receive the ping notification
    • call RequestLocation
    • receive the location update event and respond to the ping with the current location

    Nor this plan:

    • receive the ping notification
    • StartUpdatingLocations
    • receive the location update event and respond to the ping
    • StopUpdatingLocations

    will work - i do not get the location update event.
    i do not know if this is because initiating location monitoring from the background is disallowed or if doing so takes more time than is allowed for handling a background notification.

    The only thing that works is this:

    • StartUpdatingLocations (and get updates while in the background)
    • receive the ping notification
    • respond to the ping notification with the last reported location

    I will have to work on correct settings for DesiredAccuracy and DistanceFilter so that the app is getting the bare minimum of updates or my users will be unhappy.

    (fyi, your guess that the max allowed time for something to be in the background is definitely incorrect, i have apps that sit idle in the background for days. I can imagine that this depends on a variety of factors - how much memory other apps require, etc, but it is definitely not on the order of minutes)

  • patcarutherspatcaruthers USMember ✭✭✭

    yet another update -- relating to the failure of this method:

    • receive the ping notification
    • StartUpdatingLocations
    • receive the location update event and respond to the ping
    • StopUpdatingLocations

    It appears that the failure may have been actually my app's event handler was taking too long and the watchdog was not allowing things to finish. After a bunch of re-optimization i have found that this Does work:

    • receive the ping notification
    • StartUpdatingLocations
    • receive the location update event
    • StopUpdatingLocations
    • respond to the ping with the new location data.

    So contrary to my earlier conclusion, you can start/stop monitoring from an app running in the background.

    This method may still not work for me, because the first update location is not very accurate, but that's a different conversation.

  • patcarutherspatcaruthers USMember ✭✭✭
    Accepted Answer

    the last update on this; really.
    After i posted the above i discovered that "it worked" was "only sort of" - i got exactly 2 updates if the app was in the background when i called StartUpdatingLocations. And 2 updates are not enough for the system to get a good fix - the first update is usually just what you got the last time you asked and the second may not be much better. You need to get several - 6 or more, before you can trust the answer.

    But i found this post and the long and very information answer by g. malde is great and his suggestion of using BeginBackgroundTask works. It allows me to get updates for at least 20 seconds, which is enough.

Sign In or Register to comment.