backgroundLocation.ts 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import * as TaskManager from 'expo-task-manager';
  2. import * as Location from 'expo-location';
  3. import axios from 'axios';
  4. import { checkAndSendSavedMessages, storage, StoreType } from 'src/storage';
  5. import { Platform } from 'react-native';
  6. import NetInfo from '@react-native-community/netinfo';
  7. import { API_URL, APP_VERSION } from 'src/constants';
  8. import { API } from 'src/types';
  9. const LOCATION_TASK_NAME = 'BACKGROUND_LOCATION_TASK';
  10. TaskManager.defineTask(LOCATION_TASK_NAME, async ({ data, error }) => {
  11. if (error) {
  12. console.error('[BackgroundLocation] Task error:', error);
  13. return;
  14. }
  15. if (data) {
  16. const { locations } = data as any;
  17. let lastLocationSentTime =
  18. (storage.get('last_location_sent_time', StoreType.NUMBER) as number) ?? 0;
  19. let lastLatitude = storage.get('last_latitude', StoreType.NUMBER) as number | null;
  20. let lastLongitude = storage.get('last_longitude', StoreType.NUMBER) as number | null;
  21. if (locations && locations.length > 0) {
  22. const now = Date.now();
  23. const { coords } = locations[0];
  24. const token = storage.get('token', StoreType.STRING);
  25. if (!token) {
  26. return;
  27. }
  28. const getThreeDigits = (num: number) => Math.floor(num * 1000);
  29. const latitudeChanged =
  30. !lastLatitude || getThreeDigits(lastLatitude) !== getThreeDigits(coords.latitude);
  31. const longitudeChanged =
  32. !lastLongitude || getThreeDigits(lastLongitude) !== getThreeDigits(coords.longitude);
  33. if (latitudeChanged || longitudeChanged || now - lastLocationSentTime >= 60 * 1000) {
  34. storage.set('last_location_sent_time', now);
  35. storage.set('last_latitude', coords.latitude);
  36. storage.set('last_longitude', coords.longitude);
  37. const netInfoState = await NetInfo.fetch();
  38. if (netInfoState.isConnected) {
  39. checkAndSendSavedMessages();
  40. }
  41. try {
  42. const response = await axios.postForm(
  43. API_URL + '/' + API.UPDATE_LOCATION,
  44. {
  45. token,
  46. lat: coords.latitude,
  47. lng: coords.longitude
  48. },
  49. {
  50. headers: {
  51. Platform: Platform.OS,
  52. 'App-Version': APP_VERSION
  53. }
  54. }
  55. );
  56. } catch {}
  57. }
  58. }
  59. }
  60. });
  61. export const startBackgroundLocationUpdates = async () => {
  62. const hasStarted = await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK_NAME);
  63. if (hasStarted) {
  64. return;
  65. }
  66. await Location.startLocationUpdatesAsync(LOCATION_TASK_NAME, {
  67. accuracy: Location.Accuracy.High,
  68. // 30 minutes for Android
  69. timeInterval: 30 * 60 * 1000,
  70. showsBackgroundLocationIndicator: false,
  71. pausesUpdatesAutomatically: false,
  72. // banner on Android
  73. foregroundService: {
  74. notificationTitle: 'NomadMania tracking your location',
  75. notificationBody: 'Location is used in background every 30 minutes.'
  76. // notificationColor: '#0F3F4F'
  77. },
  78. // iOS only
  79. activityType: Location.ActivityType.Other,
  80. // 1 minute for iOS
  81. deferredUpdatesInterval: 60 * 1000
  82. });
  83. };
  84. export const stopBackgroundLocationUpdates = async () => {
  85. const hasStarted = await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK_NAME);
  86. if (hasStarted) {
  87. await Location.stopLocationUpdatesAsync(LOCATION_TASK_NAME);
  88. }
  89. };
  90. export const restartBackgroundLocationUpdates = async () => {
  91. const lastUpdatedVersion = storage.get('location_update_version', StoreType.STRING) ?? '';
  92. const hasStarted = await Location.hasStartedLocationUpdatesAsync(LOCATION_TASK_NAME);
  93. if (hasStarted && lastUpdatedVersion !== APP_VERSION) {
  94. await Location.stopLocationUpdatesAsync(LOCATION_TASK_NAME);
  95. }
  96. await startBackgroundLocationUpdates();
  97. storage.set('location_update_version', APP_VERSION);
  98. };