31

I am currently developing an app for iOS with expo sdk-version 32. I have to call a REST service periodically from my app. In order to do that I tried to utilize the new BackgroundFetch API.

Here is my Code:

const BACKGROUND_LOCATION_SENDING_TASK = "BACKGROUND_LOCATION_SENDING_TASK";

async function initBackgroundLocationSending() {
    console.log("initBackgroundLocationSending()");

    TaskManager.defineTask(BACKGROUND_LOCATION_SENDING_TASK, () => {

        // this console.log does never get called ... 
        console.log("BACKGROUND_LOCATION_SENDING_TASK");

        // i will implement real fetch logic here when i found out how to get this function called.
        return BackgroundFetch.Result.NewData;
    });

    console.log("is task registered ... ");
    let isRegistered = await TaskManager.isTaskRegisteredAsync(BACKGROUND_LOCATION_SENDING_TASK);
    console.log("isRegistered: ", isRegistered);

    if(isRegistered) {
        console.log("unregister task ...");
        await BackgroundFetch.unregisterTaskAsync(BACKGROUND_LOCATION_SENDING_TASK);
        console.log("Done");
    }

    console.log("is task registered ... ");
    isRegistered = await TaskManager.isTaskRegisteredAsync(BACKGROUND_LOCATION_SENDING_TASK);
    console.log("isRegistered: ", isRegistered);

    console.log("register task ...");
    await BackgroundFetch.registerTaskAsync(BACKGROUND_LOCATION_SENDING_TASK);
    console.log("OK");


    console.log("is task registered ... ");
    isRegistered = await TaskManager.isTaskRegisteredAsync(BACKGROUND_LOCATION_SENDING_TASK);
    console.log("isRegistered: ", isRegistered);

    console.log("set minimum interval ...");
    await BackgroundFetch.setMinimumIntervalAsync(60);
    console.log("OK");

    console.log("get status ... ");
    const status = await BackgroundFetch.getStatusAsync();
    console.log("status: ", status);
}

Console output from calling the function from within App.js:

: initBackgroundLocationSending()
: is task registered ...
: isRegistered:  true
: unregister task ...
: OK
: is task registered ...
: isRegistered:  false
: register task ...
: OK
: is task registered ...
: isRegistered:  true
: set minimum interval ...
: OK
: get status ...
: status:  3

From expo's background-fetch documentation I understand that status: 3 means BackgroundFetch.Status.Available.

the iOS section from my app.json:

...
"ios": {
  "supportsTablet": true,
  "bundleIdentifier": "xxx-yyy-zzz",
  "infoPlist": {
    "UIBackgroundModes": [
      "location",
      "fetch"
    ],
    "NSLocationWhenInUseUsageDescription": "... (replaced)",
    "NSLocationAlwaysAndWhenInUseUsageDescription": "... (replaced)",
    "NSLocationAlwaysUsageDescription": "... (replaced)"
  }
},
...

My testing device is an IPhone 6s with iOS 12.1.3.

What am I missing? Why does it not run the task at all even not after some minutes?

btw: I use expo's background location without any problems

4
  • Why was my question downvoted? Please let me know the reason so i can improve it.
    – Struemmeck
    Commented Feb 18, 2019 at 6:56
  • 3
    having the same issue, opened an issue on github about it github.com/expo/expo/issues/3582
    – Quince
    Commented Feb 27, 2019 at 7:35
  • Here's a more recent unclosed version of the issue github.com/expo/expo/issues/9900 with an MVCE Commented Feb 5, 2021 at 15:45
  • One thing you're missing is the custom Expo IOS client build expo client:ios BUT even with that I am still unable to get it to work correctly. Commented Feb 5, 2021 at 15:48

1 Answer 1

1

I would try by moving the task definitions to global scope, as documentation states, since the way you set it up currently is defined inside a function scope

  1. Define the task by providing a name and the function that should be executed Note: This needs to be called in the global scope (e.g outside of your React components)

Meaning this

const BACKGROUND_LOCATION_SENDING_TASK = "BACKGROUND_LOCATION_SENDING_TASK";

async function initBackgroundLocationSending() {
    console.log("initBackgroundLocationSending()");

    TaskManager.defineTask(BACKGROUND_LOCATION_SENDING_TASK, () => {

        // this console.log does never get called ... 
        console.log("BACKGROUND_LOCATION_SENDING_TASK");

        // i will implement real fetch logic here when i found out how to get this function called.
        return BackgroundFetch.Result.NewData;
    });

    ....

}

Should change to this

const BACKGROUND_LOCATION_SENDING_TASK = "BACKGROUND_LOCATION_SENDING_TASK";

 TaskManager.defineTask(BACKGROUND_LOCATION_SENDING_TASK, () => {

     // this console.log does never get called ... 
     console.log("BACKGROUND_LOCATION_SENDING_TASK");

     // i will implement real fetch logic here when i found out how to get this function called.
     return BackgroundFetch.Result.NewData;
 });


async function initBackgroundLocationSending() {
    console.log("initBackgroundLocationSending()");

    ...

}

The rest of initBackgroundLocationSending that handles the registration of the task should be called on component mount

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.