Location-aware Android apps with reliable geofencing
Implementing location services and geofencing in Android involves more than a map pin and radius. It needs clear permissions, a reliable location source and protection against process death, weak signals and battery restrictions. Treat each geofence entry or exit as an event-driven signal for a small, well-defined job.
This guide uses Kotlin, Google's Fused Location Provider and Geofencing API. The fused provider combines GPS, Wi-Fi and cellular signals, while the geofencing service wakes the app when a device crosses a registered boundary. Keep platform calls in a repository so screens, analytics and business rules remain independent of Android APIs.
Australian conditions make field testing especially valuable. Sydney and Melbourne have dense transit corridors, crowded retail centres and tall buildings that can block satellite signals. Perth, Adelaide, Canberra and Hobart offer different urban spreads, traffic patterns and coverage gaps, while regional roads, mining sites, farms and coastal routes add long distances and intermittent mobile data.
Treat those conditions as product requirements rather than footnotes. An Australian delivery, rideshare, safety or tourism app may need different thresholds in a busy CBD than at a regional depot. Android permission rules and Google Play policy shape a launch in the local market, while privacy expectations influence whether users will keep location access enabled.
Start with a small location architecture
Decide what the app must know before choosing an API. A foreground map may need frequent updates from FusedLocationProviderClient; a store-arrival feature usually needs only geofence transitions. Avoid a continuous stream when an event is enough, because it consumes battery and weakens the permission rationale. For continuous foreground tracking, declare the location service type and meet the current foreground-service permission rules.
Create a LocationRepository with operations such as registerFence and removeFence. Let it own GeofencingClient, the location provider and a local event store. Expose results through a Kotlin Flow, and persist accepted events so a receiver can finish work after the UI process is recreated. Check Google Play Services availability on supported devices and provide a platform fallback or state the requirement clearly.
Keep coordinates, place records and business actions separate. Give every fence a stable identifier, expiry or refresh policy, and rule for entry or exit. Resolve a readable destination from place data, but never treat a geofence match as proof of identity or consent.
Request permissions in a deliberate sequence
Start with the least access that supports the first feature. ACCESS_COARSE_LOCATION can support city-level features; add ACCESS_FINE_LOCATION only when the experience needs precise positioning. On recent Android versions, the user may grant approximate access, so test both choices and avoid UI that falsely promises street-level accuracy.
Ask for location permission in context, immediately before the user enables an arrival alert or opens a nearby-results screen. Explain the benefit in one sentence, show the system prompt without hidden pre-prompts, and provide a useful path when access is denied. If the app repeatedly asks after a refusal, direct the user to system settings instead of pressuring them.
Background location is a separate decision. If a geofence must notify users while the app is invisible, request ACCESS_BACKGROUND_LOCATION only when that behaviour is core to the feature, and check Google Play's background-location policy. On Android 13 and later, request POST_NOTIFICATIONS separately if alerts rely on notifications. For an Australian organisation covered by the Privacy Act 1988, explain what is collected, whether coordinates leave the device, retention periods and how access can be withdrawn.
Design boundaries for Australian conditions
A geofence is a circular area, not a polygon. Choose the distance at which the action should occur, then select ENTER, EXIT or DWELL for the journey. Small circles can be noisy between tall buildings; large ones fire too early in busy precincts. Stay within Play Services' limit of 100 active geofences per app and remove stale fences.
Use these operating rules when defining a fence:
- Assign a stable, non-secret identifier and a readable label; never use a raw address as the primary key.
- Choose one transition for the first release, define a minimum dwell time when useful, and record expected duplicates.
- Set expiry and refresh rules for venues, delivery stops and temporary worksites so old boundaries disappear.
Use a launch matrix that includes these Australian contexts:
- Sydney and Melbourne: test short-radius fences around stations, shopping centres and transit corridors, including indoor approaches.
- Perth, Adelaide, Canberra and Hobart: compare moderate arrival zones with city traffic, park edge cases and changing network coverage.
- Regional, mining, farming and coastal areas: allow for sparse data, long distances and power-saving settings; events may arrive late.
Store timestamps in UTC and display Australian local time, accounting for daylight-saving changes and multiple time zones. A late callback can still be matched to a trip or order, but it should not be presented as a precise instant.
Make transitions survive real device behaviour
Register fences with GeofencingClient.addGeofences, using a unique identifier and a PendingIntent aimed at a dedicated BroadcastReceiver. Include a package-specific action. On Android 12 and later, follow the Geofencing API's current PendingIntent guidance, including its required mutability flag, and keep the receiver explicit.
The receiver parses the transition type, geofence identifier and timestamp, then passes the event to the repository. Make processing idempotent because Android may retry delivery or restart the process. Send network-bound actions through a durable queue, and retain enough state to avoid duplicate notifications.
Battery optimisation, vendor restrictions and offline periods can delay callbacks. Test with the screen off, the app swiped away, Doze enabled and connectivity disabled. Use WorkManager for deferrable follow-up work, keep foreground work short, and rely on registered fences across ordinary reboots instead of a continuously running activity.
Validate, publish and grow the experience
Test with a physical Android phone rather than relying on an emulator. Exercise permission grant, approximate location, denial, background use, enter and exit transitions, duplicate callbacks, process death, reboot, airplane mode and weak GPS. Limit mock locations to the test build, and record device, Android version, app version and permission state with each event.
Measure timely alerts, missed stops, battery drain, notification dismissal and opt-out rates. Publish a privacy notice covering purpose, retention and third-party processors, then check it against Australian consumer expectations and Google Play's data-safety declarations. A staged Australian rollout can expose differences between urban and regional fences. Keep the DigitalOcean-hosted phpMyAdmin panel private and separate from the Android client.
Where a site mixes technical guidance with editorial posts, the slots bonus guide can occupy a clearly labelled related-reading slot without being mistaken for setup material. This keeps a short walkthrough distinct from the implementation instructions.
Start with one useful place, one transition and one measurable result. Add the permission rationale, register the fence, test it in the relevant Australian environment and release the smallest reliable version. Give users a clear location control, monitor the transition stream and expand from proven results.