Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expected behavior from watchPosition timeouts and high accuracy #287

Open
rolinger opened this issue Jan 7, 2025 · 4 comments
Open

Expected behavior from watchPosition timeouts and high accuracy #287

rolinger opened this issue Jan 7, 2025 · 4 comments

Comments

@rolinger
Copy link

rolinger commented Jan 7, 2025

I am testing some new rewrites of my code for geolocation and am noticing some peculiliar things and hoping others can help explain.

For both getCurrentPositions() and watchPosition() I use same following options:
var geoOptions = { maximumAge: 10000, timeout: 10000, enableHighAccuracy: true };

  1. When app is deployed to iOS Simulator and physical iPhone the watchPosition() fires a 4 times (every time) and then on the 4th call I get a timeout which is triggers my onError callback. The specific error message is Code: 3, Message: Position retrieval timed out. After 1 timeout, watchPosition() stops and does not resume. This happens on fresh install of app on either type and with simply deploying the app again (overwriting the current installed one. On physical devices and Android simulator this is not happening - I see it firing about once per second (***) continuously.

  2. When deployed a real device, watchPosition() seems to be firing every second even though my device is plugged and sitting on and not moving. How exactly is watchPosition working? I assume it would only trigger if it detected an actual movement, but my debugging shows the same coordinates every time it fires.

  3. Is there a way to slow down the watchPosition to only "check" once per 10 seconds...I don't need extreme "watching" in my app but I do need to try and update the users coordinates at certain intervals.

  4. Last, how intensive is enableHighAccuracy on the device as well as what are others experiences when not using it - the disabledHIghAccuraccy coordinates versus the enableHighAccurracy coordinates? Is there really a significant difference?

Thanks.

@breautek
Copy link
Contributor

breautek commented Jan 7, 2025

When app is deployed to iOS Simulator and physical iPhone the watchPosition() fires a 4 times (every time) and then on the 4th call I get a timeout which is triggers my onError callback.

iOS does something unique in that when you first start up the location manager, it will immediately send in "GPS updates", in whatever state it's in. These are usually garbage and/or out-dated location events but Apple favours sending them out for responsiveness vs accuracy. Android doesn't behave this way and will wait for a GPS event that is somewhat acceptable in accuracy.

After 1 timeout, watchPosition() stops and does not resume.

This is probably due to the fact that Apple wants iOS developers to stop the location manager on errors, though if it's stopping the watch on timeout, then that might be wrong on Cordova's part.

Is there a way to slow down the watchPosition to only "check" once per 10 seconds...I don't need extreme "watching" in my app but I do need to try and update the users coordinates at certain intervals.

Before I get into this, important to note that Cordova doesn't have an Android implementation. You're using the native browser geolocation implementation on Android. The android side of this plugin only handles permissions.

Android & iOS has different "energy-saving" mantras. How Android filters geolocation updates is not really known, as it's a browser implementation detail. iOS does use distance filter checks.

On both platforms, Healthy GPS connections will report a GPS update approximately every second. On iOS, GPS updates are filtered by a distance filter. These are hard-coded based on the high accuracy boolean. If I recall correctly, it's 5m for high accuracy, and 3km for coarse accuracy. GPS updates doesn't get broadcasted to app code immediately, but whenever the native GPS update is provided it is recorded and broadcasted to the webview (but not app code).

On the plugin's JS side, there is an interval that ticks every second that provides the last known GPS update. I believe it will use the timestamp and maximum age to determine whether if app-code callback should be invoked or not. It will also trigger timeouts if it hasn't received a GPS update from native within the requested timeout time. So depending on the configuration, you could see several "GPS updates" that are actually the same GPS point, if GPS updates from native are slow.

I'm kinda going off memory, I didn't review the code before I wrote this so I might have some minor details wrong...

Last, how intensive is enableHighAccuracy on the device as well as what are others experiences when not using it - the disabledHIghAccuraccy coordinates versus the enableHighAccurracy coordinates? Is there really a significant difference?

High accuracy allows "fine" location, which is necessary if you want to know the street the user is on. Just because you have enableHighAccurracy enabled, doesn't mean the user will actually grant you high accuracy permission. The user can opt to only grant coarse (low accuracy) permission.

If the boolean is off, then the option for the user to grant high accuracy location will not be shown and the user can only grant coarse accuracy (or obviously reject giving permission).

If app code enables high accuracy, and the user grants high accuracy, it is still possible that the device will only operate with coarse accuracy, depending on device location settings (for example, if using GPS hardware is turned off).

The exact accuracy Coarse option provides is implementation dependent but usually it uses more energy efficient means of determining the location, e.g. avoids using GPS hardware. Accuracy is usually guaranteed to be within 3km but is often (in my experience) much tighter radius. Even if the given point is accurate to a 3km radius, this is acceptable if you're trying to determine the user's country for example.

If you don't need high accuracy, then allowing only coarse accuracy should see energy usage improvements. The interval used on the JS side might be a bit wasteful, but most of the energy consumption will be from the GPS hardware which the settings will configure the native stuff to be more energy efficient.

@rolinger
Copy link
Author

rolinger commented Jan 7, 2025

Thanks for the informative responses. My biggest issue with iOS watchPosition() is its timing out and and not continuing on its own. Unless there is a way around this I am going to have to add code to my onError that tries to reset/restart the watchPosition() method.

@breautek
Copy link
Contributor

breautek commented Jan 7, 2025

My biggest issue with iOS watchPosition() is its timing out and and not continuing on its own. Unless there is a way around this I am going to have to add code to my onError that tries to reset/restart the watchPosition() method.

Yah that might be a bug... I know Apple wants iOS developers to stop the location manager on "denied" errors, but a timeout is likely not a deny error.

And it would definitely be better if behaviour was consistent with Android. Like I said, Android uses the browser implementation, so it's likely also more closer to the W3C spec.

@rolinger
Copy link
Author

rolinger commented Jan 7, 2025

@breautek - this is a good write up, maybe you can pin for others or add some of these details to the readme file. We can close this one, but I am going to open a BUG issue now specifically regarding the iOS watchPosition timeout behavior I am seeing; I will be referencing a work around - maybe the bug/work around here in this thread.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants