Location.startLocationUpdatesAsync() throws error with TaskManager.defineTask() not being called in global scope.

Hello everyone! Let me explain my problem with an issue template.

  1. SDK Version: 36
  2. Platforms: Android 9 (Xiaomi Redmi Note 7 MIUI11) and Android 9 emulator (Google Pixel 2)

Steps to reproduce:

  1. TaskManager.defineTask() in App.js outside of component class.
  2. Register task with Location.startLocationUpdatesAsync() anywhere (normal or async function or lifecycle method ot useEffect hook).
  3. Log gotten results inside Task.

Expected behavior:
Background task should be started. On every location update there should be logged new locations array containg freshly caught location regardless of app being open or minimized.

Actual behavior:
TaskManager.defineTask must be called during initialization phase! error is logged in the console. If Location.startLocationUpdatesAsync() is called in async function it also throws error in Client as well. Location is checked once or twice per app refresh.

My code:

import React, { Component } from 'react';
import { Platform, Text, View, StyleSheet } from 'react-native';
import Constants from 'expo-constants';
import * as Location from 'expo-location';
import * as Permissions from 'expo-permissions';
import * as TaskManager from 'expo-task-manager';

export default class App extends Component {
  state = {
    location: null,
    errorMessage: null,
  };

  constructor() {
    super();
    this._ensurePermissionGranted();
    this._startLocationUpdates();
  }
  
  _startLocationUpdates = () => {
    Location.startLocationUpdatesAsync('watch', {
      foregroundService: {
        notificationTitle: 'Geotracker',
        notificationBody: 'Tracking enabled'
      }
    });
  }

  _ensurePermissionGranted = async () => {
    let { status } = await Permissions.askAsync(Permissions.LOCATION);
    if (status !== 'granted') {
      this.setState({
        errorMessage: 'Permission to access location was denied',
      });
    }
  }

  render() {
    let text = 'Waiting..';
    if (this.state.errorMessage) {
      text = this.state.errorMessage;
    } else if (this.state.location) {
      text = JSON.stringify(this.state.location);
    }

    return (
      <View style={styles.container}>
        <Text style={styles.paragraph}>{text}</Text>
      </View>
    );
  }
}

TaskManager.defineTask('watch', ({ data: { locations = [] }, error }) => {
  if(error) {
    return console.error(error)
  }
  console.log(locations.reverse()[0]);
})

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    paddingTop: Constants.statusBarHeight,
    backgroundColor: '#ecf0f1',
  },
  paragraph: {
    margin: 24,
    fontSize: 18,
    textAlign: 'center',
  },
});

This code is as simple as it can get to show what exactly is not working. Whole project is fresh out of expo init command and code above is everything App.js consists of.

There’s definitely something wrong here. Even the example from the docs gives the same error:

https://docs.expo.io/versions/v36.0.0/sdk/task-manager/#examples

I’ve seen this too, I’m pretty sure this is caused by the new reload mechanism (Fast refresh) which ends up calling the initialization code again when updating any file, leading to this (misleading) error message. I would not worry about it.

@mustafa115 or @jerome.cornet: Could you please check if there’s already an issue for this and create one if not? Then post a comment here with a link to the issue.

There is an issue already Location.startLocationUpdatesAsync() throws error "TaskManager.defineTask() not being called in global scope" after saving changes · Issue #6619 · expo/expo · GitHub but the expo team seems to ignore the background location / background fetch bugs, which are actually broken, see Expo Location. startLocationUpdatesAsync and TaskManager.defineTask, task crash and unregistering · Issue #6017 · expo/expo · GitHub and my other posts in the forum.

OK thanks, I see @mustafa115 created the issue.

I see @charliecruzan posted a comment on the issue with a guess as to the cause and a workaround. Obviously not ideal to have to reload after changing a file, since that defeats the object of Fast Refresh, but I wouldn’t exactly call that “ignoring” the issue.

Of course #6017 has been a problem for a few months, so I can understand that it’s frustrating. Does it work in SDK 34? I wonder if it would be possible to git bisect this issue to find the commit that introduced the bug which might help with figuring out how to fix it.

Re: #6017 the feature has actually never completely worked at least on Android (I’ve been trying to use it since sdk33), but many others have reported problems since the feature was introduced, take a look at BackgroundFetch not running · Issue #3582 · expo/expo · GitHub for a timeline.

“Ignoring” may seem like a harsh characterization, but I honestly don’t know how to say this differently based on the lack of comments from the expo team on any of the related issues on github.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.