Skip to content

[Help Wanted]: Android ignores geofenceTemplate and sends default payload structure instead of custom template (works fine on iOS) + onProviderChange not triggering in background/terminated state on Android #1624

@olabissani-98

Description

@olabissani-98

Required Reading

  • Confirmed

Plugin Version

5.0.1

Mobile operating-system(s)

  • iOS
  • Android

Device Manufacturer(s) and Model(s)

SM A556E

Device operating-systems(s)

android 16

What do you require assistance about?

After upgrading to version 5.0.1, I'm experiencing two issues on Android:

geofenceTemplate is being completely ignored - Android sends the full default payload with nested objects instead of the custom template
onProviderChange event does not trigger when the app is in background or terminated state on Android

Both the geofence template feature works correctly on iOS, but the provider change issue is Android-only.

Expected Behavior (iOS - Working Correctly)
iOS sends the custom template as configured:
[
{
"mock": "false",
"userId": 6170,
"event": "geofence",
"geofenceIdentifier": "WORK",
"key": "TEST",
"lat": 33.88657231524748,
"lng": 35.51786011859788,
"timestamp": "2026-01-22T09:48:46.046Z",
"geofenceAction": "ENTER"
}
]

Actual Behavior

{
"location": [
{
"is_moving": true,
"uuid": "9bae532e-7dc2-4a7d-b60b-6c50014c76c2",
"timestamp": "2026-01-22T09:50:50.449Z",
"recorded_at": "2026-01-22T09:50:50.602Z",
"age": 0.153,
"odometer": 0,
"odometer_error": 0,
"coords": {
"latitude": 33.8865387,
"longitude": 35.5178374,
"accuracy": 11.49,
"speed": -1,
"speed_accuracy": 1.5,
"heading": -1,
"heading_accuracy": 45,
"altitude": 118.8,
"ellipsoidal_altitude": 118.8,
"altitude_accuracy": 1
},
"activity": {
"type": "still",
"confidence": 100
},
"battery": {
"is_charging": true,
"level": 0.54
},
"extras": {
"userId": 6169,
"key": "TEST"
}
}
]
}

[Optional] Plugin Code and/or Config

bg.BackgroundGeolocation.onHttp(onHttp);
  bg.BackgroundGeolocation.onProviderChange(onProviderChange);
  
  bg.BackgroundGeolocation.addGeofence(bg.Geofence(
          identifier: "WORK",
          radius: geofenceRadius,
          latitude: lat,
          longitude: lng,
          notifyOnEntry: true,
          notifyOnExit: true,
          notifyOnDwell: false))
      .then((bool success) async {
    if (success) {
      print("🟢 Geofence added successfully.");
    }
  }).catchError((error) async {
    print("Error adding geofence: $error");
  });

  bg.BackgroundGeolocation.ready(bg.Config(
    geolocation: bg.GeoConfig(
      desiredAccuracy: bg.DesiredAccuracy.high,
      distanceFilter: 10,
      locationAuthorizationRequest: "Always",
    ),
    persistence: bg.PersistenceConfig(
      maxDaysToPersist: 3,
      geofenceTemplate: '{ "lat":<%= latitude %>, "lng":<%= longitude %>,"timestamp": "<%= timestamp %>","mock": "<%= mock %>", "geofenceIdentifier":"<%= geofence.identifier %>","geofenceAction":"<%= geofence.action %>","event":"<%= event %>"}',
      extras: {
        "userId": userId,
        "key": key,
      },
      disableProviderChangeRecord: false,
    ),
    app: bg.AppConfig(
      stopOnTerminate: false,
      startOnBoot: true,
      preventSuspend: true,
      enableHeadless: true,
      backgroundPermissionRationale: bg.PermissionRationale(
          message: 'Your location information will be kept secure and will not be shared with any third-party services without your explicit consent.'),
      heartbeatInterval: 600,
    ),
    http: bg.HttpConfig(
      url:'${Generic.geofenceEvent}',,
      headers: {"content-type": "application/json"},
      rootProperty: ".",
      autoSync: true,
      batchSync: true,
    ),
    logger: bg.LoggerConfig(
      debug: true,
      logLevel: bg.LogLevel.verbose,
    ),
    activity: bg.ActivityConfig(
      activityRecognitionInterval: 0,
      stopDetectionDelay: 0,
      stopOnStationary: false,
    ),
  )).then((bg.State state) async {
    if (!state.enabled) {
      bg.BackgroundGeolocation.startGeofences();
    }
  });
}

MAIN:


@pragma('vm:entry-point')
void backgroundGeolocationHeadlessTask(bg.HeadlessEvent headlessEvent) async {
  bg.Logger.debug("====Background Headless Task:  ${headlessEvent}====");
  print('📬 --> $headlessEvent');
  
  try {
    switch (headlessEvent.name) {
      case bg.Event.GEOFENCE:
        bg.GeofenceEvent geofenceEvent = headlessEvent.event;
        print(geofenceEvent);
        break;
      case bg.Event.HTTP:
        bg.HttpEvent response = headlessEvent.event;
        print(response);
        GeofenceController.onHttp(response);
        break;
      case bg.Event.PROVIDERCHANGE:
        try {
          bg.ProviderChangeEvent event = headlessEvent.event;
          await GeofenceController.onProviderChange(event);
          print(event);
        } catch (e) {
          bg.Logger.error("Provider Change Critical Error: $e");
        }
        break;
      // ... other cases
    }
  } catch (e) {
    bg.Logger.error("====Background Headless [ ERROR ! ] Error in headless task ! : $e====");
    print("[ ERROR ! ] Error in headless task ! : $e");
  }
}

[Optional] Relevant log output

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions