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