Maps and Geolocation in Mobile Apps: Google Maps, MapKit, Geofencing, Tracking
Geolocation in mobile applications is not just "adding a map." It involves working with permissions, accuracy, power consumption, and OS-specific behavior that fundamentally differs between iOS and Android. A delivery tracker, a running app, a store locator—each scenario requires a different approach to how and when to request coordinates.
Permissions: One of the Most Common Sources of Bad Reviews
On iOS, geolocation permission is the most sensitive after microphone and camera. Since iOS 14, the system displays an indicator in the status bar when geolocation is used in the background—users notice this. NSLocationWhenInUseUsageDescription and NSLocationAlwaysAndWhenInUseUsageDescription must contain honest explanations, or the app will be rejected during review. Requesting always permission at startup is a guaranteed way to lose most users. The correct pattern: first whenInUse, then always only when the user reaches the feature that requires it, with a clear explanation of why.
On Android, API 29+ has ACCESS_BACKGROUND_LOCATION as a separate permission that cannot be requested together with foreground location. First request foreground permission, then background as a separate step. Google Play requires justification for background location in the questionnaire at publication. Weak justification may result in rejection or a requirement to remove background location support.
Accuracy and Power Consumption: How Not to Drain the Battery
Constant GPS at maximum accuracy consumes 100–150 mW—the battery drains in 4–6 hours. For most tasks, this is excessive.
On Android, FusedLocationProviderClient (Google Play Services) combines GPS, Wi-Fi, and cellular networks, selecting the optimal source. LocationRequest.Builder with priorities:
-
PRIORITY_HIGH_ACCURACY— GPS enabled, for navigation -
PRIORITY_BALANCED_POWER_ACCURACY— accuracy ~100 meters, Wi-Fi + cellular -
PRIORITY_LOW_POWER— accuracy ~10 km, cellular only -
PRIORITY_PASSIVE— coordinates from other apps, no active request
For an active running tracker, use HIGH_ACCURACY with a 2–5 second interval. For background geofence notifications, use PASSIVE or LOW_POWER; the system wakes up on events.
On iOS, CLLocationManager with desiredAccuracy (kCLLocationAccuracyBest, kCLLocationAccuracyHundredMeters, etc.) and distanceFilter—the minimum displacement in meters before the next update. For route tracking with battery savings: desiredAccuracy = kCLLocationAccuracyNearestTenMeters, distanceFilter = 10—you get updates only during actual movement.
Significant Location Changes—an iOS mode that works at the OS level without active GPS: updates when the cellular tower changes, battery impact is minimal. Accuracy ~500 meters—suitable for logging "where was the user today," not for navigation.
Google Maps SDK vs MapKit vs Mapbox vs OpenStreetMap
| SDK | Platform | Offline Maps | Custom Style | Without Google Services |
|---|---|---|---|---|
| Google Maps SDK | iOS/Android | No (Maps API only) | Yes (Cloud-based) | No |
| MapKit | iOS | No | Limited | Yes |
| Mapbox Maps | iOS/Android | Yes | Fully | Yes |
| HERE Maps | iOS/Android | Yes | Yes | Yes |
| OpenStreetMap + MapLibre | iOS/Android/Flutter | Yes | Fully | Yes |
Google Maps SDK is the default choice for most projects: familiar UI, good documentation, Directions API, Places Autocomplete. Limitation—dependency on Google Play Services (problematic for Huawei) and pricing at high request volumes.
Mapbox is preferred when you need a custom map style (corporate branding, dark theme), offline maps for offline work, or accessibility on devices without GMS. MapboxNavigation SDK—full-featured navigation with voice guidance, dynamic rerouting, lane guidance.
For Flutter: google_maps_flutter (official), flutter_map (OpenStreetMap + MapLibre, fully open-source), mapbox_maps_flutter (official Mapbox SDK since 2023).
Geofencing: Notifications by Zone
Geofencing—triggering an event when entering/exiting a geographic zone (circle with a specified radius).
On Android—GeofencingClient from Google Location Services. Add Geofence objects with setTransitionTypes(GEOFENCE_TRANSITION_ENTER | GEOFENCE_TRANSITION_EXIT) and PendingIntent to BroadcastReceiver. Limitation: maximum 100 active geofences per app, minimum radius ~150 meters (in practice due to accuracy), triggering with delays up to several minutes for battery optimization.
On iOS—CLCircularRegion + CLLocationManager.startMonitoring(for:). Limit: 20 regions per app. The OS controls when to check—the developer doesn't control the delay. For more precise geofencing with small radius—use iBeacon (CLBeaconRegion) or CLVisit for places where the user spent time.
If you need more than 20 (iOS) or 100 (Android) zones—you need server-side logic: periodically send coordinates to the server, the server checks zone hits and sends push notifications. Less precise in timing, but scales to thousands of zones.
Route Tracking and Background Geolocation
Tracking a running route or courier route in the background are technically different tasks.
On iOS, background geolocation works through UIBackgroundModes: location in Info.plist. Without this key, when the app goes to background, CLLocationManager gets a few minutes and sleeps. With the key—it works constantly, but the system may pause on critically low battery.
For a running tracker on iOS, the pattern is: startUpdatingLocation at workout start, write coordinates to Core Data every 5 seconds, on pause—stopUpdatingLocation, but keep startMonitoringSignificantLocationChanges so the app doesn't get "lost" entirely.
On Android, for courier tracking, you need a Foreground Service with FOREGROUND_SERVICE_TYPE_LOCATION (mandatory with API 29+). A foreground service shows a persistent notification—this is a platform requirement, not a bug. Without it, Android Doze will kill location updates. WorkManager for background tasks doesn't fit here—it doesn't guarantee continuity.
The algorithmic part of route tracking: raw GPS coordinates are noisy. For smoothing—use the Ramer-Douglas-Peucker algorithm to simplify the track or Kalman Filter for real-time noise filtering. Without filtering, the track looks like random zigzags, and the calculated distance is 20–30% more than actual.
Scope and Timeframe
Basic map integration with markers and address search—1–2 weeks. Geofencing with push notifications—2–3 weeks including testing on real devices (the emulator poorly simulates geofencing delays). Full route tracking with background mode, smoothing, and server synchronization—4–6 weeks.







