Skip to content

[Bug]: MEDIUM Accuracy Stops Background Location Updates on Android #2610

@bala-asteride

Description

@bala-asteride

Required Reading

  • Confirmed

Plugin Version

5.1.1

Mobile operating-system(s)

  • iOS
  • Android

Device Manufacturer(s) and Model(s)

Motorola Edge 50 Fusion

Device operating-systems(s)

Android 16

React Native / Expo version

No response

What happened?

On Android, background location tracking stops delivering onLocation events when desiredAccuracy is set to MEDIUM and the tracking screen loses focus. Switching to HIGH accuracy restores correct behaviour immediately. The foreground service notification stays visible, giving a false impression that tracking is active.

Expected Behaviour

MEDIUM accuracy should continue delivering location updates on Android when the screen that started tracking loses focus, consistent with HIGH accuracy behaviour.

Actual Behaviour

onLocation events stop firing entirely when desiredAccuracy is MEDIUM and the Android Activity's screen is no longer focused. The foreground service notification remains visible, giving a false impression of active tracking. No error or warning is emitted.


Additional Notes

  • iOS is unaffected — both MEDIUM and HIGH behave correctly on iOS.
  • The Android Fused Location Provider (FLP) appears to deprioritise MEDIUM accuracy requests when the requesting Activity loses focus. HIGH forces the GPS hardware directly and is not subject to this deprioritisation.
  • Workaround: Use HIGH accuracy. This increases battery consumption (~8× vs MEDIUM) which is undesirable for long-duration ride tracking.
  • Setting fastestLocationUpdateInterval to a lower value (e.g. 500ms) does not resolve the issue with MEDIUM.

Plugin Code and/or Config

# `app/_layout.tsx`


import { Stack } from "expo-router";
import { useEffect, useRef } from "react";
import BackgroundGeolocation, {
  Subscription,
} from "react-native-background-geolocation";
import { TrackingProvider, useTracking } from "../contexts/tracking";

function BackgroundGeolocationSetup() {
  const { setIsTracking } = useTracking();
  const subscriptions = useRef<Subscription[]>([]);

  useEffect(() => {
    const subs = subscriptions.current;

    subs.push(
      BackgroundGeolocation.onLocation((location) => {
        console.log("[onLocation]", location);
      }),
    );
    subs.push(
      BackgroundGeolocation.onEnabledChange((enabled) => {
        setIsTracking(enabled);
      }),
    );

    // ⚠️ Bug: change MEDIUM → HIGH to observe the difference
    BackgroundGeolocation.ready({
      geolocation: {
        desiredAccuracy: BackgroundGeolocation.DesiredAccuracy.Medium, // ❌ breaks background updates
        distanceFilter: 1,
      },
      android: {
        locationUpdateInterval: 1000,
        fastestLocationUpdateInterval: 2000,
      },
      app: {
        heartbeatInterval: 60,
        stopOnTerminate: false,
        startOnBoot: true,
      },
      logger: {
        debug: true,
        logLevel: BackgroundGeolocation.LogLevel.Verbose,
      },
    }).then((state) => {
      setIsTracking(state.enabled);
    });

    return () => subs.forEach((s) => s.remove());
  }, [setIsTracking]);

  return null;
}

export default function RootLayout() {
  return (
    <TrackingProvider>
      <BackgroundGeolocationSetup />
      <Stack>
        <Stack.Screen name="index" options={{ title: "Home" }} />
        <Stack.Screen name="settings" options={{ title: "Settings" }} />
      </Stack>
    </TrackingProvider>
  );
}


### `app/index.tsx`


import { router } from "expo-router";
import { Pressable, StyleSheet, Text, View } from "react-native";
import BackgroundGeolocation from "react-native-background-geolocation";
import { useTracking } from "../contexts/tracking";

export default function IndexScreen() {
  const { isTracking } = useTracking();

  const onToggleTracking = async () => {
    const state = await BackgroundGeolocation.getState();
    if (state.enabled) {
      await BackgroundGeolocation.stop();
    } else {
      await BackgroundGeolocation.start();
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.status}>
        {isTracking ? "✅ Tracking active" : "❌ Tracking inactive"}
      </Text>

      {/* Navigate away to trigger the bug — onLocation stops firing */}
      <Pressable style={styles.button} onPress={() => router.push("/settings")}>
        <Text style={styles.buttonText}>Go to Settings (triggers bug)</Text>
      </Pressable>

      <Pressable style={styles.button} onPress={onToggleTracking}>
        <Text style={styles.buttonText}>
          {isTracking ? "Stop Tracking" : "Start Tracking"}
        </Text>
      </Pressable>
    </View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, alignItems: "center", justifyContent: "center", gap: 16 },
  status: { fontSize: 16, fontWeight: "600" },
  button: {
    backgroundColor: "#007AFF",
    paddingVertical: 14,
    paddingHorizontal: 24,
    borderRadius: 8,
    minWidth: 220,
    alignItems: "center",
  },
  buttonText: { color: "#fff", fontSize: 15, fontWeight: "600" },
});


---

## Config Comparison

###  Broken  `MEDIUM` accuracy


BackgroundGeolocation.ready({
  geolocation: {
    desiredAccuracy: BackgroundGeolocation.DesiredAccuracy.Medium,
    distanceFilter: 1,
  },
  android: {
    locationUpdateInterval: 1000,
    fastestLocationUpdateInterval: 2000,
  },
});


`onLocation` fires normally while the screen is focused. As soon as the user navigates to another screen, events stop completely. No error is thrown.

###  Works  `HIGH` accuracy


BackgroundGeolocation.ready({
  geolocation: {
    desiredAccuracy: BackgroundGeolocation.DesiredAccuracy.High, // only change
    distanceFilter: 1,
  },
  android: {
    locationUpdateInterval: 1000,
    fastestLocationUpdateInterval: 2000,
  },
});

Relevant log output

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions