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