Expo GPS Location + Task Manager
Tags: reactnative, expo, location
Published: 2024-01-04 07:06:22

React Native Expo has a great package called `expo-location` which lets your app to access gps location in your react native app.

`npx expo install expo-location`

As we want to track gps even when the app is in the background, we would need task manager. Install it by:

`npx expo install expo-task-manager`

Now, create a new custom hook called `useGPS` like:

```javascript
export default function useGPS() {
  const [locationStarted, setLocationStarted] = React.useState(false);

  useEffect(() => {
    (async () => {
      const res = await Location.requestForegroundPermissionsAsync();
      if (!res.granted)
        console.log('Foreground permission not granted!')

      const task = TaskManager.isTaskDefined(LOCATION_TRACKING);
      if (!task)
        console.log('TASK not defined')
    })();

  }, [])

  const startLocationTracking = async () => {
    await Location.startLocationUpdatesAsync(LOCATION_TRACKING, {
      accuracy: Location.Accuracy.Highest,
      timeInterval: 5000,
      distanceInterval: 0,
      foregroundService: {
        notificationTitle: 'MY_GPS_APP',
        notificationBody: "Location is used when running app",
      },
    }).catch(e => console.log('error in startlocationasync = ', e));

    const hasStarted = await Location.hasStartedLocationUpdatesAsync(
      LOCATION_TRACKING
    );
    setLocationStarted(hasStarted);
  };

  const startLocation = () => {
    startLocationTracking();
  }

  const stopLocation = () => {

    setLocationStarted(false);
    TaskManager.isTaskRegisteredAsync(LOCATION_TRACKING)
      .then((tracking) => {
        if (tracking) {
          Location.stopLocationUpdatesAsync(LOCATION_TRACKING);
        }
      })
  }
  return { startLocation, stopLocation, locationStarted }
}
```

The parameters of `Locatin.startLocationUpdatesAsync()` are very important. If you do not pass `foregroundService` then the built apk will not work and you will see error in console saying,

>Not authorized to use background location services.

Hence this is important

```
foregroundService: {
  notificationTitle: 'MY_GPS_APP',
  notificationBody: "Location is used when running app",
```

In your view component, import the useGPS hook we created and call startLocation() on a button press, like:

```javascript
function GPSView() {
  const { startLocation, stopLocation, locationStarted } = useGPS()

return (
    <View>
        <Button title="Stop Tracking" onPress={() => {
          stopLocation();
         }
        }></Button>
        <Button title="Start Tracking" onPress={startLocation}> 
        </Button>
    </View>)
}
```
Task Manager is defined like this, and can be placed in any file, preferably at an entry file.

```javascript

TaskManager.defineTask(LOCATION_TRACKING, async ({ data, error }) => {
  if (error) {
    console.log('LOCATION_TRACKING task ERROR:', error);
    return;
  }
  if (data) {
    const { locations } = data;
    let lat = locations[0].coords.latitude;
    let long = locations[0].coords.longitude;

    console.log(
      `${new Date(Date.now()).toLocaleString()}: ${lat},${long}`
    );
  }
});
```
Build your app with expo
>npx expo start

and you will see console log of your location.