jamesisaac / react-native-background-task

Periodic background tasks for React Native apps, cross-platform (iOS and Android), which run even when the app is closed.
MIT License
1.11k stars 110 forks source link
android background-jobs fetch ios offline react-native sync

react-native-background-task

npm version license npm downloads

Periodic background tasks for React Native apps, cross-platform (iOS and Android), which run even when the app is closed.

This library allows the scheduling of a single periodic task, which executes when the app is in the background or closed, no more frequently than every 15 minutes. Network, AsyncStorage etc can be used (anything except UI), so perfect for things like a background data sync for offline support.

Behind the scenes, this library takes a different approach with each platform:

To achieve a unified API, this library exposes the lowest common denominator (e.g. only support for a single task, even though Android can support multiple).

For more per-platform flexibility, there are other platform-specific libraries with more granular customisation.

Installation

$ npm install react-native-background-task --save

Android

  1. The linking of the library can be done automatically by running:

    $ react-native link react-native-background-task
  2. One manual step is still needed - in your project file android/app/src/main/java/myapp/MainApplication.java, add the following to the end of the onCreate() method:

    BackgroundTaskPackage.useContext(this);

iOS

For iOS support, this library relies on version 2.0.x of react-native-background-fetch which can be installed as follows:

$ npm install react-native-background-fetch@2.0.x --save
$ react-native link react-native-background-fetch

This library will behave correctly on iOS as long as react-native-background-fetch is installed alongside it, and has been linked with your project.

API

define(task)

Define the JS code that this module should be executing.

Parameters:

schedule(options)

Specify the scheduling options for the task, and register it with the platform's scheduler.

Parameters:

finish()

Must be called at the end of your task to indicate to the OS that it's finished. (Only required on iOS, no-op on Android).

cancel()

Cancels any currently scheduled task.

statusAsync()

Query the status of background tasks within this app. Returns a Promise with an object of the following shape:

Limitations

Android:

iOS:

Debugging

Android

$ adb logcat *:S ReactNative:V ReactNativeJS:V BackgroundTask:V

Keep in mind that after the app leaves the foreground, you'll have to wait at least 50% of the desired period (so, default is 7m30s) before the task executes.

Examples

A full example project can be found here: https://github.com/jamesisaac/RNBackgroundTaskExample

Simple

import React from 'react'
import { Text } from 'react-native'
import BackgroundTask from 'react-native-background-task'

BackgroundTask.define(() => {
  console.log('Hello from a background task')
  BackgroundTask.finish()
})

class MyApp extends React.Component {
  componentDidMount() {
    BackgroundTask.schedule()
  }

  render() {
    return <Text>Hello world</Text>
  }
}

Fetch / store data

import React from 'react'
import { Alert, AsyncStorage, Button } from 'react-native'
import BackgroundTask from 'react-native-background-task'

BackgroundTask.define(async () => {
  // Fetch some data over the network which we want the user to have an up-to-
  // date copy of, even if they have no network when using the app
  const response = await fetch('http://feeds.bbci.co.uk/news/rss.xml')
  const text = await response.text()

  // Data persisted to AsyncStorage can later be accessed by the foreground app
  await AsyncStorage.setItem('@MyApp:key', text)

  // Remember to call finish()
  BackgroundTask.finish()
})

class MyApp extends React.Component {
  componentDidMount() {
    BackgroundTask.schedule({
      period: 1800, // Aim to run every 30 mins - more conservative on battery
    })

    // Optional: Check if the device is blocking background tasks or not
    this.checkStatus()
  }

  async checkStatus() {
    const status = await BackgroundTask.statusAsync()

    if (status.available) {
      // Everything's fine
      return
    }

    const reason = status.unavailableReason
    if (reason === BackgroundTask.UNAVAILABLE_DENIED) {
      Alert.alert('Denied', 'Please enable background "Background App Refresh" for this app')
    } else if (reason === BackgroundTask.UNAVAILABLE_RESTRICTED) {
      Alert.alert('Restricted', 'Background tasks are restricted on your device')
    }
  }

  render() {
    return (
      <View>
        <Button
          title="Read results from AsyncStorage"
          onPress={async () => {
            const result = await AsyncStorage.getItem('@MyApp:key')
            console.log(result) 
          }}
        />
      </View>
    )
  }
}