jamesmontemagno / GeolocatorPlugin

Geolocation plugin for Xamarin and Windows
MIT License
293 stars 158 forks source link

iOS Locations differ (by a lot) from Android #318

Open ludas96 opened 4 years ago

ludas96 commented 4 years ago

We're trying to get the location while driving using this plugin, but it seems that Android and iOS differs A LOT. iOS never comes close to the actual distance while Android is working just fine.

It's not like iOS is constantly off, it's just that some points fly away into nowhere (sometimes 500meters to 1km off)

This has been the cause over several versions and we've basically tried everything at this point - I even tried to use the Xamarin.Essentials Geolocation plugin with my own timer set to an interval, but even that gave the same results. This makes me wonder if there's any known (unknown to me at least) issues with iOS and GPS accuracy? There's also the case when using Apple CarPlay, the accuracy is spot on for iOS.

Scenario where it occurred: I drove about 70km with two phones next to me (Android 10 on S10+, and iOS 13 on iPhone 7, however the iOS version doesn't matter at all, as we've tried several different iPhones & iOS versions, all giving the same result) and the Android version gave me a distance of about 70km +- 1km which is good enough for this case. The iOS version however gave me a distance of 96km (!).

The following code-snippets are what I believe the necessary information that you need. I could not post much more due to work, however if there's anything else you'd need - feel free to ask.

Note! When I used the Essentials-plugin, I used their own "Distance"-method to calculate distance between two points. And even that gave me a distance way off the actual one.

Bug Information

Version Number of Plugin: 4.5.0.6 Device Tested On: Many Android devices (Android 6+) & iOS (several versions) Version of Xamarin: 4.2.0

Code snippet

await CrossGeolocator.Current.StartListeningAsync(TimeSpan.FromSeconds(5),10, true, new ListenerSettings
{
    ActivityType = ActivityType.AutomotiveNavigation,
    AllowBackgroundUpdates = true,
    DeferLocationUpdates = true,
    DeferralDistanceMeters = 10,
    DeferralTime = TimeSpan.FromSeconds(5),
    PauseLocationUpdatesAutomatically = false
}); 

// Calculating distance OnLocationChanged:
private double DistanceTo(GPSPoint pos1, GPSPoint pos2, char unit = 'K')
{
    double rlat1 = Math.PI * pos1.Latitude / 180;
    double rlat2 = Math.PI * pos2.Latitude / 180;
    double theta = pos1.Longitude - pos2.Longitude;
    double rtheta = Math.PI * theta / 180;
    double dist =
        Math.Sin(rlat1) * Math.Sin(rlat2) + Math.Cos(rlat1) *
        Math.Cos(rlat2) * Math.Cos(rtheta);
    dist = Math.Acos(dist);
    dist = dist * 180 / Math.PI;
    dist = dist * 60 * 1.1515;

    switch (unit)
    {
        case 'K': //Kilometers -> default
            return dist * 1.609344;
        case 'M': //Miles
            return dist;
    }

    return dist;
}

// OnLocationChanged:
private async void OnLocationChanged(object sender, PositionEventArgs e)
{
    Speed = ConvertSpeed(e.Position.Speed, 'K'); 

    var pos = new GPSPoint
    {
        Longitude = e.Position.Longitude,
        Latitude = e.Position.Latitude,
        Speed = Speed,
        Timestamp = e.Position.Timestamp.LocalDateTime
    };

    CultureInfo invC = CultureInfo.InvariantCulture;
    int currentAllowedSpeed = API_CALL_FOR_ALLOWED_SPEED;  
    pos.AllowedSpeed = currentAllowedSpeed;
    AllowedSpeed = currentAllowedSpeed;

    if (!_running)
        return;

    // Remove identical points as locationAPI can trigger twice for same GPSPoint
    if (_lastPoint == null || !_lastPoint.Timestamp.Equals(pos.Timestamp))
    {
        App.PointList.Add(pos);

        if(_lastPoint != null && !_lastPoint.Timestamp.Equals(pos.Timestamp) && _lastPoint.AllowedSpeed != -1000)
            Distance += DistanceTo(_lastPoint, pos);
    }

    _lastPoint = pos;
}