Flutter Geolocator returns different coordinates on iOS vs Android for same physical location, causing inconsistent reverse geocoding address
I'm using the geolocator package in Flutter to get the current location and then reverse geocode it to a display address. The same physical device location returns noticeably different coordinates on iOS and Android, which causes the geocoded address to differ between platforms.
Getting current position:
dart
return await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
Reverse geocoding (Google Maps Geocoding API):
dart
static Future<String> getAddressFromLatLng(String? lat, String? lng) async {
final double roundedLat = double.parse(double.parse(lat!).toStringAsFixed(5));
final double roundedLng = double.parse(double.parse(lng!).toStringAsFixed(5));
final uri = Uri.parse(
'https://maps.googleapis.com/maps/api/geocode/json'
'?latlng=$roundedLat,$roundedLng'
'&key=$apiKey'
'&language=en',
);
final response = await http.get(uri);
final data = json.decode(response.body);
return data['results'][0]['formatted_address'];
}
iOS:
Got current location: 22.685498910314223, 75.85949381064067
Rounded: 22.6855, 75.85949
Resolved address: Mangal Nagar, Indore, 452014
Android (same room, same time):
Got current location: 22.685553, 75.8595931
Rounded: 22.68555, 75.85959
Resolved address: AB Road, Vishnu Puri Colony, Indore, 452014
Rounding coordinates to 5 decimal places before the API call — coordinates are still ~10–15 meters apart after rounding, enough to cross a street boundary
Switching from formatted_address to address_components — skipping street_number and route, only using sublocality, locality, postal_code — still getting different neighborhood names
Filtering result_type=neighborhood|sublocality in the geocoding request — partially helped but still inconsistent
Why does LocationAccuracy.high produce coordinates ~10–15 meters apart between iOS and Android on the same physical location?
Is there a reliable way to get consistent coordinates across both platforms using geolocator?
Should I be averaging multiple position readings to stabilize the result, and if so what is the recommended approach?
Flutter: 3.x
geolocator: ^13.x
Device tested: iPhone 14 (iOS 17) + Samsung Galaxy (Android 13)
Same physical location, same time
// Root cause:
// iOS (CoreLocation) and Android (FusedLocationProvider) use different sensors,
// fusion algorithms, and map matching → ~5–20m variance is NORMAL.
// You cannot force identical coordinates across platforms.
//
// Solution approach:
// 1. Take multiple samples
// 2. Filter by accuracy
// 3. Average coordinates
// 4. Optionally snap to a grid to stabilize reverse geocoding
import 'dart:async';
import 'dart:math';
import 'package:geolocator/geolocator.dart';
class StableLocationService {
static const int sampleCount = 5;
static const double maxAccuracyMeters = 25;
static Future<Position> getStablePosition() async {
List<Position> samples = [];
while (samples.length < sampleCount) {
final pos = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.high,
);
if (pos.accuracy <= maxAccuracyMeters) {
samples.add(pos);
}
await Future.delayed(const Duration(milliseconds: 500));
}
return _averagePosition(samples);
}
static Position _averagePosition(List<Position> positions) {
double lat = 0;
double lng = 0;
for (var p in positions) {
lat += p.latitude;
lng += p.longitude;
}
lat /= positions.length;
lng /= positions.length;
return Position(
latitude: lat,
longitude: lng,
timestamp: DateTime.now(),
accuracy: positions.map((e) => e.accuracy).reduce(min),
altitude: 0,
heading: 0,
speed: 0,
speedAccuracy: 0,
altitudeAccuracy: 0,
headingAccuracy: 0,
);
}
// Snap to grid (~10m) to avoid crossing street boundaries
static double snap(double value, double gridSizeMeters) {
const earthRadius = 6378137.0;
double gridDegrees = gridSizeMeters / earthRadius * (180 / pi);
return (value / gridDegrees).round() * gridDegrees;
}
static Map<String, double> getSnappedLatLng(
double lat,
double lng, {
double gridMeters = 10,
}) {
return {
"lat": snap(lat, gridMeters),
"lng": snap(lng, gridMeters),
};
}
}
// Usage:
//
// final pos = await StableLocationService.getStablePosition();
// final snapped = StableLocationService.getSnappedLatLng(
// pos.latitude,
// pos.longitude,
// );
//
// Use snapped["lat"], snapped["lng"] for reverse geocoding.
//
// Result:
// - Reduces platform variance
// - Prevents street-boundary flips
// - Produces consistent addresses across iOS & Android