← Home

How to run background tasks in Expo React Native

June 12, 2020

Expo is a great tool for developing mobile applications with React Native, especially for beginners, but this power has consequences and limits. some features cannot be implemented without detaching from Expo.


Update - December 30, 2021

🚀 Since the release of Expo 42, it has become limitless in the managed workflow.

👉 Check out this example on how to edit Android manifest file in Expo!


In this article, we are going to show the default way to do tasks in the background, without detaching from the expo, and the tricky way using React Native Webview.

Using task manager

To make background tasks work in IOS, we need to add the following configuration to the app.json file:

{
  "expo": {
    ...
    "ios": {
      "infoPlist": {
        "UIBackgroundModes": ["location", "fetch"]
      }
    }
  }
}

Then we have to install the required packages, we use expo install instead of npm install to ensure we are installing the versions of the dependencies that are compatible with our Expo SDK.

expo install expo-background-fetch expo-task-manager

Importing our packages:

import * as BackgroundFetch from "expo-background-fetch"
import * as TaskManager from "expo-task-manager"

This way we define our task, it must be outside of any component.

const TASK_NAME = "BACKGROUND_TASK"

TaskManager.defineTask(TASK_NAME, () => {
  try {
    // fetch data here...
    const receivedNewData = "Simulated fetch " + Math.random()
    console.log("My task ", receivedNewData)
    return receivedNewData
      ? BackgroundFetch.Result.NewData
      : BackgroundFetch.Result.NoData
  } catch (err) {
    return BackgroundFetch.Result.Failed
  }
})

Then we create our task register function which will be called once the main component is mounted.

RegisterBackgroundTask = async () => {
  try {
    await BackgroundFetch.registerTaskAsync(TASK_NAME, {
      minimumInterval: 5, // seconds,
    })
    console.log("Task registered")
  } catch (err) {
    console.log("Task Register failed:", err)
  }
}

Here is the console output when the application is in the background.

Task registered
My task Simulated fetch 0.722435766683574
My task Simulated fetch 0.7553518044351863

Using webview

In a previous article in dev.to, I already talked about running background audio in React Native specifically Expo using WebView, here is another trick for running background tasks.

Installing webview:

expo install react-native-webview

Create a background-task component:

import * as React from "react"
import { WebView } from "react-native-webview"

function BackgroundTask(props) {
  return (
    <WebView
      onMessage={props.function}
      source={{
        html: `<script>
          setInterval(()=>{window.ReactNativeWebView.postMessage("");}, ${props.interval})
          </script>`,
      }}
    />
  )
}
export default BackgroundTask

Using the background-task component:

import * as React from "react";
import BackgroundTask from "./BackgroundTask";

export default class App extends React.Component {
  ...
  render() {
    return (
      ...
      <BackgroundTask
        interval={1000}
        function={() => {
          console.log("My task " + Math.random();
        }}
      />
    );
  }
}

Comparison

Here is what I got while testing the two methods.

Expo background task:

  • Works in background
  • Works when app closed
  • Updates randomly, it does not follow the given interval
  • Works in IOS and Android

Webview background task:

  • Works in background and foreground
  • Does not work when app is closed
  • Update regularly following the given interval
  • Works in Android but not recent IOS versions

👉 Want to track the GPS position in the background or in the foreground, check out this article.


Chafik Gharbi Full-stack web and mobile app developer with JavaScript.