Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Geofencing in background on Android 8 or 9 does not work

I try to make appear a push alert to the user when he reach a defined zone.

So I coded my app from : https://developer.android.com/training/location/geofencing

It is working perfectly if my app is running with a service following the location of the user.

It also work if I start google map for example, that will track my location too. Pushes will appear.

But if I close my app the push won't appear, so the geofencing is not detected if no app is tracking my location.

Is it normal ? How to make it work always ? What is the point of geofencing if you need a foreground service following your location ?

 public void createGeofenceAlerts(LatLng latLng, int radius) {
    final Geofence enter = buildGeofence(ID_ENTER, latLng, radius, Geofence.GEOFENCE_TRANSITION_ENTER);
    final Geofence exit = buildGeofence(ID_EXIT, latLng, radius, Geofence.GEOFENCE_TRANSITION_EXIT);
    final Geofence dwell = buildGeofence(ID_DWELL, latLng, radius, Geofence.GEOFENCE_TRANSITION_DWELL);

    GeofencingRequest request = new GeofencingRequest.Builder()
            .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER)
            .addGeofence(enter)
            .addGeofence(exit)
            .addGeofence(dwell)
            .build();

    fencingClient.addGeofences(request, getGeofencePendingIntent()).addOnSuccessListener(new OnSuccessListener<Void>() {
        @Override
        public void onSuccess(Void aVoid) {
            Timber.i("succes");
            Toast.makeText(mContext, "Geofence added", Toast.LENGTH_LONG).show();
        }
    }).addOnFailureListener(new OnFailureListener() {
        @Override
        public void onFailure(@NonNull Exception e) {
            Timber.e(e,"failure");
            Toast.makeText(mContext, "Geofence ERROR", Toast.LENGTH_LONG).show();
        }
    });
}

private PendingIntent getGeofencePendingIntent() {
    Intent intent = new Intent(mContext, GeofenceTransitionsIntentService.class);
    PendingIntent pending = PendingIntent.getService(
            mContext,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT);
    return pending;
}

private Geofence buildGeofence(String id, LatLng center, int radius, int transitionType) {
    Geofence.Builder builder = new Geofence.Builder()
            // 1
            .setRequestId(id)
            // 2
            .setCircularRegion(
                    center.getLatitude(),
                    center.getLongitude(),
                    radius)
            // 3
            .setTransitionTypes(transitionType)
            // 4
            .setExpirationDuration(Geofence.NEVER_EXPIRE);
    if (transitionType == Geofence.GEOFENCE_TRANSITION_DWELL) {
        builder.setLoiteringDelay(LOITERING_DELAY);
    }

    return builder.build();
}
like image 373
Ben-J Avatar asked Jan 24 '19 13:01

Ben-J


People also ask

What permissions does my app need to use geofencing?

To use geofencing, your app must request the following: ACCESS_BACKGROUND_LOCATION if your app targets Android 10 (API level 29) or higher To learn more, see the guide on how to request location permissions .

How often does my Android device respond to geofence events?

Note: On Android 8.0 (API level 26) and higher, if an app is running in the background while monitoring a geofence, then the device responds to geofencing events every couple of minutes. To learn how to adapt your app to these response limits, see Background Location Limits .

How do I enable geofence monitoring on my App?

The first step in requesting geofence monitoring is to request the necessary permission. To use geofencing, your app must request ACCESS_FINE_LOCATION. If your app targets Android 10 (API level 29) or higher, your app must also request ACCESS_BACKGROUND_LOCATION.

Where are registered geofences kept in Android?

Registered geofences are kept in the com.google.process.location process owned by the com.google.android.gms package. The app doesn’t need to do anything to handle the following events, because the system restores geofences after these events: Google Play services is upgraded.


2 Answers

I have been working with GeoFence for such a long time, I had the same question and I got the answer by myself after trying different solutions, So basically, GeoFence only get triggers if any app in the phone is fetching the location for some x duration. If you test the GeoFence sample app provided by google then you can see that the app works only when you open the Google maps application, its because Google Maps is the only app in the device that requests locations passively.

For Prove you can clone GeoFence sample and the LocationUpdateForGroundService sample from this below link https://github.com/googlesamples/android-play-location Run both of them GeoFence and LocationUpdateForGroundService at the same time, You will notice by changing the lat and long from the emulator that now you dont need to open Google maps any more because now there is another app which is requesting location.

So do create a foreground service in the GeoFence application and use Fuse Location Client to request location updates for some x duration.

like image 123
Mudassir Zulfiqar Avatar answered Oct 17 '22 21:10

Mudassir Zulfiqar


I discovered that my geoFenceBroadCastReceiver started to work correctly in the emulator when I had google maps open. I simply could not figure out what the problem was, and as it turns out, I was missing a piece of the puzzle obviously. The behavior is also described in this question (aptly titled): Geofence Broadcast Receiver not triggered but when I open the google map, it works, as well as filed numerous times as an issue in the Android Location Samples project Issue 239, Issue 247 Issue 266.

I don't see the actual answer to this problem posted as an answer here, so for posterity I will provide some suggestions. Issue 264 seems to point to the solution, i.e. using a JobIntentService

BUT

There's a code comment in the GeoFence Sample LocationUpdateIntentService

Note: Apps running on "O" devices (regardless of targetSdkVersion) may receive updates less frequently than the interval specified in the {@link com.google.android.gms.location.LocationRequest} when the app is no longer in the foreground.

that seems to confirm what @Vinayak points out in his answer here

O.S will not allow app to get location update from background. Implement geofence location code on foreground service. It will run as expected

The geofence broadcast receiver isn't allowed to get timely location updates (apparently even in an IntentService). You'll have to run location client in a foreground service that's requesting fine location access to get more accurate/timely geoFence triggering. So seemingly the right answer is to run the geoFence in a foreGroundService.

If you go the foreGroundService route, you'll also need to create a Notification Channel, as otherwise, you'll run into problems like this one.

See Also:

https://developer.android.com/guide/components/foreground-services

https://developer.android.com/training/location/change-location-settings#location-request

https://developer.android.com/training/location/request-updates

https://developers.google.com/android/reference/com/google/android/gms/location/FusedLocationProviderClient.html#requestLocationUpdates(com.google.android.gms.location.LocationRequest,%20com.google.android.gms.location.LocationCallback)

like image 44
Loose Cannon Avatar answered Oct 17 '22 21:10

Loose Cannon