Marci-man
Marci-man

Reputation: 2233

How to deal with background geofencing in 2022?

Here is the situation:

When a user creates a Geofence, I save it to backend and I register a Geofence with the OS. But whenever my app restarts I fetch geofences from my backend and reregister them with the OS again, since they keep disappearing.

I have two classes MainActivity and FormActivity. Both of these activities register Geofences, so I have extracted the actual registration to an ordinary POJO Geofences.java

Here is the problem:

Now the strange thing is, triggers are only received when a map activity is on the screen. I do have a map activity in my app, but it doesn't even have to be my map-activity, even if I launch google maps geofence triggers start firing.

What am I doing wrong?

Geofences.java:

public class Geofences {

    private final String TAG = Geofences.class.getSimpleName();
    private final float RADIUS = 150.0F; //meter
    private boolean success = false;

    private final int LOITERING_IN_MILLISECONDS = 30000;// 30 seconds

    public boolean doGeofenceStuff(GeoTemp newTemp, String geofenceId, PendingIntent pendingIntent, GeofencingClient geofencingClient) {

        Geofence geofence = createGeofence(newTemp, geofenceId);
        GeofencingRequest geofencingRequest = createGeofenceRequest(geofence);
        geofencingClient.addGeofences(geofencingRequest, pendingIntent)
                .addOnCompleteListener(new OnCompleteListener<Void>() {
                    @Override
                    public void onComplete(@NonNull Task<Void> task) {
                        if (task.isSuccessful()) {
                            success = true;
                            Log.i(TAG, "onComplete: DEBUG-Message: Geofence has been added.");

                        } else {
                            success = false;
                            Log.i(TAG, "onComplete: Geofence could not be added");
                        }
                    }
                }); // handle error here
        return success;
    }

    // Create a Geofence
    private Geofence createGeofence(GeoTemp geoTemp, String geofenceId) {


        long expiration = getExpirationForCurrentGeofence();
        if (expiration < 1) {
            Log.e(TAG, "createGeofence: Can't create Geofence, since expiration is less than zero");
            return null;
        }
        Log.d(TAG, "createGeofence");
        return new Geofence.Builder()
                .setRequestId(geofenceId)
                .setCircularRegion(getLat(), getLong(), RADIUS)
                .setExpirationDuration(expiration)
                .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_DWELL | Geofence.GEOFENCE_TRANSITION_EXIT)
                .setLoiteringDelay(LOITERING_IN_MILLISECONDS)
                .build();
    }

    // Create a Geofence Request
    private GeofencingRequest createGeofenceRequest(Geofence geofence) {
        Log.d(TAG, "createGeofenceRequest");
        return new GeofencingRequest.Builder()
                .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_DWELL)
                .addGeofence(geofence)
                .build();
    }

}

This POJO Geofences.java is then used by two of my activities:

MainActivity:

public class MainActivity extends AppCompatActivity {

    private static String TAG = "MainActivity";
    private final int GEOFENCE_REQ_CODE = 0;
    private GeofencingClient geofencingClient;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        geofencingClient = LocationServices.getGeofencingClient(this);
        getCurrentTemps();
    }

    private void refreshGeofence(GeoTemp temp, String id) {
        new Geofences().doGeofenceStuff(temp, id, createGeofencePendingIntent(), geofencingClient);
    }
    private void getCurrentTemps() {
        List<GeoTemp> currentGeofences = getUpdatedList();
        currentGeofences.forEach(geoTemp -> {
            refreshGeofence( geoTemp, id);
        });
    }
    private PendingIntent createGeofencePendingIntent() {
        Log.d(TAG, "createGeofencePendingIntent");
        Intent intent = new Intent(this, LocationAlertIntentService.class);
        return PendingIntent.getService(
                this, GEOFENCE_REQ_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }
}

There is one more activity which uses Geofences.java to register geofences with the operating system.

Update:

I have found out that, if any other app (including mine) requests for location lock, geofence triggers fire. I need them to fire in the background.

Upvotes: 4

Views: 1499

Answers (1)

Arslan Shoukat
Arslan Shoukat

Reputation: 439

I had similar issue when working with geofencing in android.

This happens due to background restrictions added in Android Oreo and later.

OS does not allow your app to start service when it is in background so you won't receive geofence trigger.

To handle this:

  • Add broadcast receiver to receive intent. (This receiver will get geofence alert even when app is in background)
  • Replace service with JobIntentService. (This will use OS JobSchedular and run even with background restrictions)
  • Get broadcast from pending intent instead of service.

Checkout this sample project for further clarifications.

Upvotes: 2

Related Questions