/** * Sample React Native App * https://github.com/facebook/react-native * * Generated with the TypeScript template * https://github.com/react-native-community/react-native-template-typescript * * @format */ import React from 'react'; import { SafeAreaView, ScrollView, StatusBar, StyleSheet, Text, View, Switch, Button, Alert, PermissionsAndroid, // ToastAndroid, NativeModules, } from 'react-native'; import BackgroundFetch from 'react-native-background-fetch'; import Geolocation, { GeolocationError, GeolocationResponse, } from '@react-native-community/geolocation'; const {ForegroundHeadlessModule} = NativeModules; const Colors = { gold: '#fedd1e', black: '#000', white: '#fff', lightGrey: '#ccc', blue: '#337AB7', brick: '#973920', }; /// Util class for handling fetch-event peristence in AsyncStorage. import Event from './src/Event'; import AsyncStorage from '@react-native-async-storage/async-storage'; Geolocation.setRNConfiguration({ skipPermissionRequests: true, locationProvider: 'auto', }); const requestPermissions = async () => { try { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION, { title: 'Need permission to access location', message: 'Location access is needed ' + 'so we can track your location!', buttonNegative: 'Cancel', buttonPositive: 'OK', }, ); const granted2 = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION, { title: 'Need permission to access location', message: 'Location access is needed ' + 'so we can track your location!', buttonNegative: 'Cancel', buttonPositive: 'OK', }, ); if ( granted === PermissionsAndroid.RESULTS.GRANTED && granted2 === PermissionsAndroid.RESULTS.GRANTED ) { console.log('You can use the location'); } else { console.log('Location permission denied'); } } catch (err) { console.warn(err); } }; function geoLocationPromise(): Promise { return new Promise((resolve, reject) => { Geolocation.getCurrentPosition( info => { console.log(info); resolve(info); }, error => { console.log(error); reject(error); }, { timeout: 20000, maximumAge: 0, // enableHighAccuracy: true, }, ); }); } const App = () => { const [enabled, setEnabled] = React.useState(false); const [status, setStatus] = React.useState(-1); const [events, setEvents] = React.useState([]); React.useEffect(() => { async function asyncTask() { await requestPermissions(); initBackgroundFetch(); loadEvents(); } asyncTask(); }, []); /// Configure BackgroundFetch. /// const initBackgroundFetch = async () => { const status: number = await BackgroundFetch.configure( { minimumFetchInterval: 15, // <-- minutes (15 is minimum allowed) stopOnTerminate: false, enableHeadless: true, startOnBoot: false, // Android options forceAlarmManager: false, // <-- Set true to bypass JobScheduler. requiredNetworkType: BackgroundFetch.NETWORK_TYPE_NONE, // Default requiresCharging: false, // Default requiresDeviceIdle: false, // Default requiresBatteryNotLow: false, // Default requiresStorageNotLow: false, // Default }, async (taskId: string) => { console.log('[BackgroundFetch] taskId', taskId); if (taskId === 'react-native-background-fetch') { // console.log('[BackgroundFetch] taskId', taskId); const event = await Event.create(taskId, false); // Update state. setEvents(prev => [...prev, event]); } if (taskId === 'com.transistorsoft.customtask') { // Geolocation.getCurrentPosition( // async info => { // console.log(info); // const event = await Event.create(taskId, false, `lat-${info.coords.latitude};long-${info.coords.longitude}`); // }, // err => console.log(err), // { // timeout: 10000, // maximumAge: 10000, // enableHighAccuracy: false, // }, // ); try { const locInfo = (await geoLocationPromise()) as GeolocationResponse; const event = await Event.create( taskId, false, `lat-${locInfo.coords.latitude};long-${locInfo.coords.longitude}`, ); // Update state. setEvents(prev => [...prev, event]); } catch (error) { const g = error as GeolocationError; if (g.message) { const event = await Event.create(taskId, false, `${g.message}`); // Update state. setEvents(prev => [...prev, event]); } else { const event = await Event.create(taskId, false); // Update state. setEvents(prev => [...prev, event]); } } // console.log('Running [customtask] here!'); } // Finish. BackgroundFetch.finish(taskId); }, (taskId: string) => { // Oh No! Our task took too long to complete and the OS has signalled // that this task must be finished immediately. console.log('[Fetch] TIMEOUT taskId:', taskId); BackgroundFetch.finish(taskId); }, ); setStatus(status); setEnabled(true); }; /// Load persisted events from AsyncStorage. /// const loadEvents = () => { Event.all() .then(data => { setEvents(data as Event[]); }) .catch(error => { Alert.alert('Error', 'Failed to load data from AsyncStorage: ' + error); }); }; /// Toggle BackgroundFetch ON/OFF /// const onClickToggleEnabled = (value: boolean) => { setEnabled(value); if (value) { BackgroundFetch.start(); } else { BackgroundFetch.stop(); } }; /// [Status] button handler. /// const onClickStatus = () => { BackgroundFetch.status().then((status: number) => { let statusConst = ''; switch (status) { case BackgroundFetch.STATUS_AVAILABLE: statusConst = 'STATUS_AVAILABLE'; break; case BackgroundFetch.STATUS_DENIED: statusConst = 'STATUS_DENIED'; break; case BackgroundFetch.STATUS_RESTRICTED: statusConst = 'STATUS_RESTRICTED'; break; } Alert.alert('BackgroundFetch.status()', `${statusConst} (${status})`); }); }; /// [scheduleTask] button handler. /// Schedules a custom-task to fire in 5000ms /// const onClickScheduleTask = () => { const delay = 600000; BackgroundFetch.scheduleTask({ taskId: 'com.transistorsoft.customtask', stopOnTerminate: false, enableHeadless: true, delay: delay, forceAlarmManager: false, periodic: true, }) .then(() => { Alert.alert( 'scheduleTask', 'Scheduled task with delay: ' + delay + 'ms', ); }) .catch(error => { Alert.alert('scheduleTask ERROR', error); }); }; /// Clear the Events list. /// const onClickClear = () => { Event.destroyAll(); setEvents([]); }; /// Fetch events renderer. /// const renderEvents = () => { if (!events.length) { return ( Waiting for BackgroundFetch events... ); } return events .slice() .reverse() .map(event => ( {event.taskId} {event.isHeadless ? '[Headless]' : ''} Remark - {event.location} {event.timestamp} )); }; async function onLocPress(): Promise { try { // const locInfo = (await geoLocationPromise()) as GeolocationResponse; // ToastAndroid.show( // `lat-${locInfo.coords.latitude};long-${locInfo.coords.longitude}`, // 5000, // ); ForegroundHeadlessModule.startService(); console.log('Did it run?'); } catch (error) { const g = error as GeolocationError; if (g.message) { console.log(g.message); } else { console.log(error); } } } function onLocStop() { ForegroundHeadlessModule.stopService(); AsyncStorage.getItem('watchId', (err, result) => { if (err) { console.log('Couldnt get WatchID', err); return; } console.log(result); if (result) { Geolocation.clearWatch(+result); } }); } return ( BGFetch Demo