4

I'm building a sports app with Expo / React Native and trying to figure out a good way to track user location while the app is in the background. I have built a solution with expo-location (https://docs.expo.io/versions/latest/sdk/location/#locationstartlocationupdatesasynctaskname-options) which successfully receives location updates, and I even managed to send the location updates to the UI with the help of an EventEmitter.

Now the problem here is, the Expo Location task keeps the location updates deferred for a VERY long time (like 12 minutes) before sending a location update to the UI. This is despite setting all the relevant options to zero or very small.

I would love to use Expo Location because I got it mostly working, but unbelievably it seems that the library lacks an option/tool to force the background task to send updates often enough (like once in 5 seconds).

I would be grateful if anyone had a solution to really making the Expo background location send updates often enough. Now it sends updates "when I feel like it", about once in 5 or 12 minutes, despite setting all the relevant options and parameters I found in the documentation.

I already came to the conclusion that Expo background location is practically broken and I should switch to another location library (https://github.com/mauron85/react-native-background-geolocation). However I'm using Expo managed workflow and installing this mauron85 location library (otherwise really promising) doesn't work, because it requires setting manually dependencies --> I need to eject from Expo managed workflow --> ejecting breaks my project structure in a way I don't know how to solve. Really frustrating!

Relevant parts of my code:

top part:

import * as Location from 'expo-location';
import * as TaskManager from 'expo-task-manager';
import EventEmitter from 'EventEmitter'

const locationEmitter = new EventEmitter();

const BACKGROUND_LOCATION_TRACKER = 'BACKGROUND_LOCATION_TRACKER'
const LOCATION_UPDATE = 'LOCATION_UPDATE'

componentDidMount after requesting location permissions:

await Location.startLocationUpdatesAsync(BACKGROUND_LOCATION_TRACKER, {
            accuracy: LocationAccuracy.BestForNavigation,
            timeInterval: 0,  // all set to 0 to make it update as often as possible!!! doesn't help
            distanceInterval: 0,
            deferredUpdatesInterval: 0, 
            deferredUpdatesDistance: 0,
            showsBackgroundLocationIndicator: true,
            foregroundService: {
                notificationTitle: 'title',
                notificationBody: 'recording',
                notificationColor: '#008000',
            },
            // pausesUpdatesAutomatically: true,

        });

    locationEmitter.on(LOCATION_UPDATE, (locationData) => {
        console.log('locationEmitter locationUpdate fired! locationData: ', locationData);
        let coordinatesAmount = locationData.newRouteCoordinates.length - 1;
        this.setState({
            latitude: locationData.newRouteCoordinates[coordinatesAmount - 1].latitude,
            longitude: locationData.newRouteCoordinates[coordinatesAmount - 1].longitude,
            routeCoordinates: this.state.routeCoordinates.concat(locationData.newRouteCoordinates)
        })
    })

define location task:

TaskManager.defineTask(BACKGROUND_LOCATION_TRACKER, async ({ data, error }) => {
    if (error) {
        console.error(error);
        return;
    }

    if (data) {
        const { locations } = data;
        console.log('backgroundLocationTracker received new locations: ', locations)

        // const [location] = locations;
        const locationsLength = locations.length;

        const newRouteCoordinates = [];
        // const totalNewDistance = 0.0;

        for (i = 0; i < locationsLength; i++) {
            const { latitude, longitude } = locations[i].coords;
            const tempCoords = {
                latitude,
                longitude,
            };
            newRouteCoordinates.push(tempCoords);
            // totalNewDistance += GLOBAL.screen1.calcDistance(newRouteCoordinates[i], newRouteCoordinates[i - 1])  
        };

        console.log('backgroundLocationTracker: latitude ', locations[locationsLength - 1].coords.latitude,
            ', longitude: ', locations[locationsLength - 1].coords.longitude, ', routeCoordinates: ', newRouteCoordinates,
            ', prevLatLng: ', newRouteCoordinates[locationsLength - 1]);

        let locationData = { newRouteCoordinates }

        locationEmitter.emit(LOCATION_UPDATE, locationData)

    }

});

As I said, it all WORKS (!) in the sense that I do get location updates from the background to the UI. The only problem here is that I can't figure out how to make the background task send location updates more often! It just keeps collecting a huge batch of 50+ location updates for even 10+ minutes before it bothers to send them to the UI!

All help appreciated, thanks.

ajupar
  • 91
  • 1
  • 3
  • 1
    Have you had any success with this. I want to stay in the managed workflow because I don't have enough understanding of going to bare workfklow – Jean Roux Aug 17 '21 at 19:05
  • @JeanRoux No success with this for now. I decided to pause this project for now and be content with having just foreground location tracking work. I will get back to it probably sometime this autumn and keep looking for solutions. – ajupar Aug 20 '21 at 08:48
  • 1
    Thanks @ajupar. It seems like the best option here is to eject and go reactive-native without expo and use a third party library like mauron85. Also just going to stick with foreground location for now. – Jean Roux Aug 23 '21 at 07:25
  • @JeanRoux Yes, mauron85 seems like the best library currently. I stumbled into other problems while trying to eject and asked about it here on Stackoverflow as well as Expo forums. I got an answer on Expo forums which might be useful to you as well: https://forums.expo.dev/t/problem-installing-location-module-how-to-link-modules-with-expo-managed-workflow/54716 – ajupar Aug 24 '21 at 08:09
  • @ajupar did you ever come to a solution for this? Its still an issue in 2023. The task location DOES work in background, but background location updates become sporadic and eventually batched (up to 30, depending on interval settings). Really dont want to eject and use the mauron85 library... but feeling its inevitable. – tudor14 Jun 03 '23 at 22:51
  • Sorry, I haven't returned to this because it was a course project and I got the credits from it as it currently is. Then other concerns took my attention. It seems my question/problem is relevant to others too, which is good. I might still get back to this out of pure interest but not sure when I have the time. My suspicion was that the library I used was not in a very mature stage, I guessed it might get improved by time or better libraries show up. Interesting to hear that it's still an issue. If I ever get back to this and find something interesting, I'll update here. :-) – ajupar Jun 26 '23 at 06:31

1 Answers1

2

I thought I would have to eject from expo too, but I changed my options and now it updates just as I intended. The problem was the acuracy, I switched to "best for navigation" just as your example and it worked. Here is my options, I think you should try to define some milisseconds, don't leave interval at 0 and don't set distance interval nor defered distance:

{accuracy: Location.Accuracy.BestForNavigation,
            timeInterval: 1000,
            showsBackgroundLocationIndicator: true,
            foregroundService:{
                notificationTitle: "Covid Tracker",
                notificationBody: "Rastreando sua localização",
                notificationColor: "#AA1111"
            },
            deferredUpdatesInterval: 100
        }
  • With these settings the updates are initially triggered with the desired frequency, but after about 15 minutes in background (with screen off and usb cable disconnected) the updates frequency will be decreased by the operating system due to energy saving reasons, at least on my redmi 9. With usb power cable connected, the updates trigger regularly. – Alex Oct 28 '22 at 16:17