1import AsyncStorage from '@react-native-async-storage/async-storage'; 2import { useFocusEffect } from '@react-navigation/native'; 3import format from 'date-format'; 4import * as BackgroundFetch from 'expo-background-fetch'; 5import * as TaskManager from 'expo-task-manager'; 6import React from 'react'; 7import { StyleSheet, Text, View } from 'react-native'; 8 9import Button from '../components/Button'; 10import useAppState from '../utilities/useAppState'; 11 12const BACKGROUND_FETCH_TASK = 'background-fetch'; 13const LAST_FETCH_DATE_KEY = 'background-fetch-date'; 14 15export default function BackgroundFetchScreen() { 16 const [isRegistered, setIsRegistered] = React.useState<boolean>(false); 17 const [fetchDate, setFetchDate] = React.useState<Date | null>(null); 18 const [status, setStatus] = React.useState<BackgroundFetch.Status | null>(null); 19 const appState = useAppState(null); 20 21 React.useEffect(() => { 22 if (appState === 'active') { 23 refreshLastFetchDateAsync(); 24 } 25 }, [appState]); 26 27 const onFocus = React.useCallback(() => { 28 refreshLastFetchDateAsync(); 29 checkStatusAsync(); 30 }, []); 31 useFocusEffect(onFocus); 32 33 const refreshLastFetchDateAsync = async () => { 34 const lastFetchDateStr = await AsyncStorage.getItem(LAST_FETCH_DATE_KEY); 35 36 if (lastFetchDateStr) { 37 setFetchDate(new Date(+lastFetchDateStr)); 38 } 39 }; 40 41 const checkStatusAsync = async () => { 42 const status = await BackgroundFetch.getStatusAsync(); 43 const isRegistered = await TaskManager.isTaskRegisteredAsync(BACKGROUND_FETCH_TASK); 44 setStatus(status); 45 setIsRegistered(isRegistered); 46 }; 47 48 const toggle = async () => { 49 if (isRegistered) { 50 await BackgroundFetch.unregisterTaskAsync(BACKGROUND_FETCH_TASK); 51 } else { 52 await BackgroundFetch.registerTaskAsync(BACKGROUND_FETCH_TASK, { 53 minimumInterval: 60, // 1 minute 54 stopOnTerminate: false, 55 startOnBoot: true, 56 }); 57 } 58 setIsRegistered(!isRegistered); 59 }; 60 61 const renderText = () => { 62 if (!fetchDate) { 63 return <Text>There was no BackgroundFetch call yet.</Text>; 64 } 65 return ( 66 <View style={{ flexDirection: 'column', alignItems: 'center' }}> 67 <Text>Last background fetch was invoked at:</Text> 68 <Text style={styles.boldText}>{format('yyyy-MM-dd hh:mm:ss:SSS', fetchDate)}</Text> 69 </View> 70 ); 71 }; 72 73 return ( 74 <View style={styles.screen}> 75 <View style={styles.textContainer}> 76 <Text> 77 Background fetch status:{' '} 78 <Text style={styles.boldText}>{status ? BackgroundFetch.Status[status] : null}</Text> 79 </Text> 80 </View> 81 <View style={styles.textContainer}>{renderText()}</View> 82 <Button 83 buttonStyle={styles.button} 84 title={isRegistered ? 'Unregister BackgroundFetch task' : 'Register BackgroundFetch task'} 85 onPress={toggle} 86 /> 87 </View> 88 ); 89} 90 91BackgroundFetchScreen.navigationOptions = { 92 title: 'Background Fetch', 93}; 94 95TaskManager.defineTask(BACKGROUND_FETCH_TASK, async () => { 96 const now = Date.now(); 97 98 console.log(`Got background fetch call at date: ${new Date(now).toISOString()}`); 99 await AsyncStorage.setItem(LAST_FETCH_DATE_KEY, now.toString()); 100 101 return BackgroundFetch.Result.NewData; 102}); 103 104const styles = StyleSheet.create({ 105 screen: { 106 flex: 1, 107 justifyContent: 'center', 108 alignItems: 'center', 109 }, 110 button: { 111 padding: 10, 112 marginVertical: 5, 113 }, 114 textContainer: { 115 margin: 10, 116 }, 117 boldText: { 118 fontWeight: 'bold', 119 }, 120}); 121