import * as TaskManager from 'expo-task-manager'; import * as Location from 'expo-location'; import axios from 'axios'; import { checkAndSendSavedMessages, storage, StoreType } from 'src/storage'; import { Platform } from 'react-native'; import NetInfo from '@react-native-community/netinfo'; import { API_URL, APP_VERSION } from 'src/constants'; import { API } from 'src/types'; const LOCATION_TASK_NAME = 'BACKGROUND_LOCATION_TASK'; TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => { if (error) { console.error('[BackgroundLocation] Task error:', error); return; } if (data) { const { locations } = data as any; let lastLocationSentTime = (storage.get('last_location_sent_time', StoreType.NUMBER) as number) ?? 0; let lastLatitude = storage.get('last_latitude', StoreType.NUMBER) as number | null; let lastLongitude = storage.get('last_longitude', StoreType.NUMBER) as number | null; if (locations && locations.length > 0) { const now = Date.now(); const { coords } = locations[0]; const token = storage.get('token', StoreType.STRING); if (!token) { return; } const getThreeDigits = (num: number) => Math.floor(num * 1000); const latitudeChanged = !lastLatitude || getThreeDigits(lastLatitude) !== getThreeDigits(coords.latitude); const longitudeChanged = !lastLongitude || getThreeDigits(lastLongitude) !== getThreeDigits(coords.longitude); if (latitudeChanged || longitudeChanged || now - lastLocationSentTime >= 60 * 1000) { storage.set('last_location_sent_time', now); storage.set('last_latitude', coords.latitude); storage.set('last_longitude', coords.longitude); const netInfoState = await NetInfo.fetch(); if (netInfoState.isConnected) { checkAndSendSavedMessages(); } try { const response = await axios.postForm( API_URL + '/' + API.UPDATE_LOCATION, { token, lat: coords.latitude, lng: coords.longitude }, { headers: { Platform: Platform.OS, 'App-Version': APP_VERSION } } ); } catch {} } } } }); export const startBackgroundLocationUpdates = async () => { const hasStarted = await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK_NAME); if (hasStarted) { return; } await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, { accuracy: Location.Accuracy.High, // 30 minutes for Android timeInterval: 30 * 60 * 1000, showsBackgroundLocationIndicator: false, pausesUpdatesAutomatically: false, // banner on Android foregroundService: { notificationTitle: 'NomadMania tracking your location', notificationBody: 'Location is used in background every 30 minutes.' // notificationColor: '#0F3F4F' }, // iOS only activityType: Location.ActivityType.Other, // 1 minute for iOS deferredUpdatesInterval: 60 * 1000 }); }; export const stopBackgroundLocationUpdates = async () => { const hasStarted = await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK_NAME); if (hasStarted) { await Location.stopLocationUpdatesAsync(LOCATION_TASK_NAME); } }; export const restartBackgroundLocationUpdates = async () => { const lastUpdatedVersion = storage.get('location_update_version', StoreType.STRING) ?? ''; const hasStarted = await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK_NAME); if (hasStarted && lastUpdatedVersion !== APP_VERSION) { await Location.stopLocationUpdatesAsync(LOCATION_TASK_NAME); } await startBackgroundLocationUpdates(); storage.set('location_update_version', APP_VERSION); };