Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: track user geolocation in background mode #285

Open
VTSingle opened this issue Nov 24, 2023 · 8 comments
Open

Android: track user geolocation in background mode #285

VTSingle opened this issue Nov 24, 2023 · 8 comments
Labels
question Further information is requested

Comments

@VTSingle
Copy link

Hey team,

Did someone found a way, how to track user geolocation in background mode?
I implemented it on IOS and it's work perfectly without any extra libraries.
But on Android it's doesn't work.

Can someone help me or give a advice?

Thank you!

@VTSingle VTSingle added the question Further information is requested label Nov 24, 2023
@shuklaharshit
Copy link

Hey can you tell me how did you got it done in ios(code snippets), what are the caveats and did you do something extra for it ?thanks

@OfryL
Copy link

OfryL commented Jan 30, 2024

Hey, you can use react-native-background-timer to do it
example/src/configs/BackgroundLocationUpdates.tsx

@shuo-hiwintech
Copy link

嘿,你可以使用example/src/configs/BackgroundLocationUpdates.tsxreact-native-background-timer来做到这一点

HI, can you please tell me if this example works in both android and ios?

@SergioGCarvalho
Copy link

@shuo-hiwintech i tried, not working, gets timeout if you try get a new location on background

@ivanoikon
Copy link

Are there any other solutions/packages to get background position? Using getPosition with background timer lead to a lot of timeout errors

@quan118
Copy link

quan118 commented Sep 25, 2024

I've just created a fork that includes support for background location updates:
https://github.com/quan118/react-native-geolocation

@ivanoikon
Copy link

ivanoikon commented Sep 26, 2024

I've just created a fork that includes support for background location updates: https://github.com/quan118/react-native-geolocation

I made some tests but unfortunately it has the same issues i found with react-native-geolocation-service + rn-foreground-service... on Android 14 after 10-15 seconds background position updates stop with no reason (foreground service seems alive). Thank you @quan118

@artemkhalygov
Copy link

artemkhalygov commented Sep 27, 2024

I found a solution, that finally works for me. It's required to install 'react-native-background-actions'

First of all, you need to add these permissions to AndroidManifest.xml

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

After that, you should ask the user to allow tracking of his location. Important that you should ask it one by one.

async function requestMultiplePermissions() {
  try {
    await PermissionsAndroid.requestMultiple([
      PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
    ])
    await PermissionsAndroid.requestMultiple([
      PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION,
    ])
    await PermissionsAndroid.requestMultiple([
      PermissionsAndroid.PERMISSIONS.ACCESS_COARSE_LOCATION,
    ])
  } catch (err) {
    console.warn('Permission request error:', err)
  }
}

And need to configure the background task.

import { useEffect } from 'react'
import { PermissionsAndroid, AppState } from 'react-native'
import BackgroundJob from 'react-native-background-actions'
import Geolocation from '@react-native-community/geolocation'

const getLocationTask = async (taskData: any) => {
  // Define a function to get the current position
  // const getCurrentPosition = () => new Promise((resolve, reject) => {
  //   Geolocation.getCurrentPosition(
  //     (position) => {
  //       console.log('Current Position:', position)
  //       resolve()
  //     },
  //     (error) => {
  //       console.log('Geolocation error:', error.code, error.message)
  //       reject(error)
  //     },
  //     { enableHighAccuracy: true, timeout: 15000, maximumAge: 10000 },
  //   )
  // })

  await new Promise((resolve) => {
    const intervalId = setInterval(async () => {
      if(!BackgroundJob.isRunning()) {
        clearInterval(intervalId) // Stop the interval if the background job is no longer running
        resolve()
        return
      }

      try {
        // await getCurrentPosition()
        await BackgroundJob.updateNotification({ taskDesc: 'Getting position...' })
      } catch (error) {
        console.log('Error getting position:', error)
      }
    }, 60 * 1000) // Get position every minute
  })
}
const options = {
  taskName: 'Gelocation Task',
  taskTitle: 'Fetching User Location',
  taskDesc: 'Fetching User Location background and foreground',
  taskIcon: {
    name: 'ic_launcher',
    type: 'mipmap',
  },
  color: theme.colors.primary,
  linkingURI: 'icansdriver://',
  parameters: {
    delay: 1000,
  },
}

// Function to start the background job
export const startBackgroundJob = async () => {
  try {
    console.log('Trying to start background service')
    await BackgroundJob.start(getLocationTask, options)
    console.log('Background service started successfully!')
  } catch (e) {
    console.log('Error starting background service:', e)
  }
}

// Function to stop the background job
export const stopBackgroundJob = async () => {
  try {
    console.log('Stopping background service')
    await BackgroundJob.stop()
    console.log('Background service stopped successfully!')
  } catch (e) {
    console.log('Error stopping background service:', e)
  }
}


export default function RequestGeolocation() {
  useEffect(() => {
    requestMultiplePermissions()

    AppState.addEventListener('change', nextAppState => {
      if(nextAppState === 'background') {
        startBackgroundJob()
      } else {
        stopBackgroundJob()
      }
    })
    // Configure Geolocation
    Geolocation.setRNConfiguration({
      authorizationLevel: 'always', // Request "always" location permission
      skipPermissionRequests: false, // Prompt for permission if not granted
    })

    // Watch for position updates
    const watchId = Geolocation.watchPosition(
      position => {
        console.log(position)
      // Send the position data to the server
      },
      error => {
        console.log(error)
      },
      {
        enableHighAccuracy: true,
        distanceFilter: 100, // Minimum distance (in meters) to update the location
        interval: 60 * 1000, // Update interval (in milliseconds), which is 15 minutes
        fastestInterval: 30 * 1000, // Fastest update interval (in milliseconds)
        accuracy: {
          android: 'highAccuracy',
          ios: 'best',
        },
        showsBackgroundLocationIndicator: true,
        pausesLocationUpdatesAutomatically: false,
        activityType: 'fitness', // Specify the activity type (e.g., 'fitness' or 'other')
        useSignificantChanges: false,
        deferredUpdatesInterval: 0,
        deferredUpdatesDistance: 0,
        foregroundService: {
          notificationTitle: 'Tracking your location',
          notificationBody: 'Enable location tracking to continue', // Add a notification body
        },
      },
    )

    // To stop tracking (for example, when the component unmounts):
    return () => {
      Geolocation.clearWatch(watchId)
    }
  }, [])
  return null
}

In the code above you can uncomment const getCurrentPosition and get coordinates by timer, or you can remove this part of the code and use Geolocation.watchPosition instead. Even without adding it to the task it would watch location changes in background mode, because you have all permissions to do it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

8 participants