react-native-geolocation-service
react-native-geolocation-service copied to clipboard
Location doesn't update when mobile in background or screen locked?
Location doesn't update in watch position.location updating in foreground only.it's stop location tracking when app goes to background in Android? Track only when in foreground. enableHighAccuracy:true,showLocationDialog:false,interval:5000,fastestInterval:2000,distanceFilter:2
https://github.com/Agontuk/react-native-geolocation-service/issues/102 https://github.com/Agontuk/react-native-geolocation-service/issues/99 https://github.com/Agontuk/react-native-geolocation-service/issues/80
Thanks for suggestion @oakis
This library does not track the state of the application. You should use Headless JS for doing background work and call geolocation API there.
Thank you @Agontuk
Would it work if I use BackgroundTimer library?
Right now I'm using @react-native-community/geolocation
but I sometimes I get the timeout error, I found a configuration that works but when the app goes to the background or the device is locked I start getting the timeout error again until I open the app.
I would like to know if someone is having this issue?
This library does not track the state of the application. You should use Headless JS for doing background work and call geolocation API there.
Say we have a watchPosition()
in our App.js and it gives us locations when app is in foreground
We want to watch positions even in background or terminated state What do we need to do in our headless task ? Do we need another watch statement like the following?
let backgroundGeo = async (event) => {
Geolocation.watchPosition() // yet another watch?
}
AppRegistry.registerHeadlessTask('backgroundGeo', () => backgroundGeo);
let backgroundGeo = async (event) => { Geolocation.watchPosition() // yet another watch? } AppRegistry.registerHeadlessTask('backgroundGeo', () => backgroundGeo);
You should just implement it once inside HeadlessTask and use that in the UI.
@Agontuk how to implement it, could u show sample snippet codes?
@lyseiha i'm working in that now, i think if you create a headlessTask executed each minute for example, and in react native side you register headlesstask for tun Geolocation.getCurrentPosition works.
i'm going to test now!
Works, but getCurrentPosition return the same value always
in options, with maximumAge: 0 works fine, some data duplicated but works fine...
@felansu how to implement it, share some code example?
Sure!
index.js react-native
async function test1(data) {
console.log('Test1 executed!')
const token = data.token;
const options = {
maximumAge: 0,
enableHighAccuracy: true,
showLocationDialog: true,
forceRequestLocation: true,
};
Geolocation.getCurrentPosition((position) => {
const geoData = {...position.coords, timestamp: position.timestamp, mocked: position.mocked};
Geolocation.stopObserving();
axios.post(API_APP_BASE_URL + 'userGeolocation/create', {geoData, token})
.then(() => {
console.log('saved')
})
.catch(error => {
console.log('error', error)
});
},
(error) => {
console.log(error.code, error.message);
},
options
);
}
AppRegistry.registerHeadlessTask('UserGeolocation', () => test1);
In java

Package
public class UserGeolocationPackage implements ReactPackage {
@NotNull
@Override
public List<NativeModule> createNativeModules(@NotNull ReactApplicationContext reactContext) {
return Collections.singletonList(new UserGeolocationModule(reactContext));
}
@NotNull
@Override
public List<ViewManager> createViewManagers(@NotNull ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
Module
public class UserGeolocationModule extends ReactContextBaseJavaModule {
private static final String REACT_CLASS = "UserGeolocation";
private static ReactApplicationContext reactContext;
UserGeolocationModule(@Nonnull ReactApplicationContext reactContext) {
super(reactContext);
UserGeolocationModule.reactContext = reactContext;
}
@Nonnull
@Override
public String getName() {
return REACT_CLASS;
}
@ReactMethod
public void startService(String token, int delayMillis) {
Intent intent = new Intent(reactContext, UserGeolocationService.class);
intent.putExtra("token", token);
intent.putExtra("delayMillis", delayMillis);
reactContext.startService(intent);
}
}
The service:
public class UserGeolocationService extends Service {
private static final String CHANNEL_ID = "USERGEOLOCATION";
private static final int SERVICE_NOTIFICATION_ID = 101010;
private static String token;
private static int delayMillis;
private Handler handler = new Handler();
private Runnable runnableCode = new Runnable() {
public void run() {
Context context = getApplicationContext();
Intent intent = new Intent(context, UserGeolocationEventService.class);
if (token != null) {
intent.putExtra("token", token);
}
context.startService(intent);
HeadlessJsTaskService.acquireWakeLockNow(context);
handler.postDelayed(this, delayMillis);
}
};
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
this.handler.removeCallbacks(this.runnableCode);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Bundle extras = intent.getExtras();
if (extras != null) {
token = extras.getString("token");
delayMillis = extras.getInt("delayMillis");
}
this.handler.post(this.runnableCode);
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Felansu Project")
.setContentText("That works!")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(contentIntent)
.setOngoing(true)
.build();
startForeground(SERVICE_NOTIFICATION_ID, notification);
return START_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_ID, importance);
channel.setDescription("GPS data");
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
}
And the UserGeolocationEventService
public class UserGeolocationEventService extends HeadlessJsTaskService {
@Nullable
protected HeadlessJsTaskConfig getTaskConfig(Intent intent) {
Bundle extras = intent.getExtras();
return new HeadlessJsTaskConfig(
"UserGeolocation",
extras != null ? Arguments.fromBundle(extras) : Arguments.createMap(),
5000,
true);
}
}
And finally start the service from react native:
UserGeolocation.startService(token, GPS_DELAY_MILIS);
I put the example with token because i use that for get in test1 function, i dont need more for save the data. If you detect an error with that logic, please tell me.
Thanks!
@felansu Thanks for your support
@felansu Thanks for your support
Please, test and tell me if works with you 🕺
Hello @felansu, Is it working in background and location also update? but yesterday i try it's show location lat and lng always the same number.
Hello @ramkiakil anything update?
I'm facing lot of issues,did you try this
not yet trying it, but i will try it tonight. i am trying to do another thing but hmm alot of issues.
@lyseiha Guys, my final solution has been create a ListenableWorker (that can be executed each >= 15 minutes). In my ReactContextBaseJavaModule i have:
import androidx.work.Data;
import androidx.work.PeriodicWorkRequest;
import androidx.work.WorkManager;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nonnull;
public class UserGeolocationModule extends ReactContextBaseJavaModule {
private static final String REACT_CLASS = "UserGeolocation";
private static ReactApplicationContext reactContext;
UserGeolocationModule(@Nonnull ReactApplicationContext reactContext) {
super(reactContext);
UserGeolocationModule.reactContext = reactContext;
}
@Nonnull
@Override
public String getName() {
return REACT_CLASS;
}
@ReactMethod
public void startWorker() {
PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest
.Builder(UserGeolocationWorker.class,
PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS,
TimeUnit.MILLISECONDS)
.addTag("UserGeolocationWorker");
Data.Builder data = new Data.Builder();
data.putString("keyOfField", "youCanPutDataHere");
builder.setInputData(data.build());
PeriodicWorkRequest periodicWorkRequest = builder.build();
WorkManager.getInstance(reactContext).enqueue(periodicWorkRequest);
}
}
and in ListenableWorker have:
import android.content.Context;
import android.location.Location;
import android.os.HandlerThread;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.concurrent.futures.CallbackToFutureAdapter;
import androidx.work.ListenableWorker;
import androidx.work.WorkerParameters;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.LocationServices;
import com.google.common.util.concurrent.ListenableFuture;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
public class UserGeolocationWorker extends ListenableWorker {
private static final String TAG = "UserGeolocationWorker";
private String keyOfField;
private FusedLocationProviderClient mFusedLocationClient;
private final HandlerThread handlerThread = new HandlerThread("RequestLocation");
public UserGeolocationWorker(@NonNull final Context appContext, @NonNull WorkerParameters workerParams) {
super(appContext, workerParams);
this.keyOfField = workerParams.getInputData().getString("keyOfField");
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(appContext);
}
private LocationCallback fusedTrackerCallback = new LocationCallback() {
@Override
public void onLocationResult(LocationResult locationResult) {
try {
Log.e(TAG, "onlocation result");
if (locationResult.getLastLocation() != null) {
Log.e(TAG, "with get last location");
Location location = locationResult.getLastLocation();
Log.e(TAG, "executing");
new OrionAsyncTask().execute(url, getPostDataString(location));
Log.e(TAG, "executed");
mFusedLocationClient.removeLocationUpdates(fusedTrackerCallback);
Log.e(TAG, "removed");
handlerThread.quit();
Log.e(TAG, "quit");
}
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "error");
e.printStackTrace();
}
}
};
@Override
public ListenableFuture<Result> startWork() {
LocationRequest locationRequest = new LocationRequest();
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
locationRequest.setFastestInterval(2000);
locationRequest.setInterval(2000);
handlerThread.start();
return CallbackToFutureAdapter.getFuture(completer -> {
Runnable runnable = () -> {
Log.e(TAG, "reuesting");
mFusedLocationClient.requestLocationUpdates(locationRequest, fusedTrackerCallback, handlerThread.getLooper());
Log.e(TAG, "completeing");
completer.set(Result.success());
Log.e(TAG, "finishing");
};
new Thread(runnable).start();
return runnable;
});
}
private String getPostDataString(Location location) throws UnsupportedEncodingException {
HashMap<String, String> params = new HashMap<>();
params.put("keyOfField", "otherValue");
params.put("latitude", location.getLatitude() + "");
params.put("longitude", location.getLongitude() + "");
params.put("accuracy", location.getAccuracy() + "");
StringBuilder result = new StringBuilder();
boolean first = true;
for (Map.Entry<String, String> entry : params.entrySet()) {
if (first)
first = false;
else
result.append("&");
result.append(URLEncoder.encode(entry.getKey(), "UTF-8"));
result.append("=");
result.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
}
return result.toString();
}
}
@lyseiha Guys, my final solution has been create a ListenableWorker (that can be executed each >= 15 minutes). In my ReactContextBaseJavaModule i have:
import androidx.work.Data; import androidx.work.PeriodicWorkRequest; import androidx.work.WorkManager; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; public class UserGeolocationModule extends ReactContextBaseJavaModule { private static final String REACT_CLASS = "UserGeolocation"; private static ReactApplicationContext reactContext; UserGeolocationModule(@Nonnull ReactApplicationContext reactContext) { super(reactContext); UserGeolocationModule.reactContext = reactContext; } @Nonnull @Override public String getName() { return REACT_CLASS; } @ReactMethod public void startWorker() { PeriodicWorkRequest.Builder builder = new PeriodicWorkRequest .Builder(UserGeolocationWorker.class, PeriodicWorkRequest.MIN_PERIODIC_INTERVAL_MILLIS, TimeUnit.MILLISECONDS) .addTag("UserGeolocationWorker"); Data.Builder data = new Data.Builder(); data.putString("keyOfField", "youCanPutDataHere"); builder.setInputData(data.build()); PeriodicWorkRequest periodicWorkRequest = builder.build(); WorkManager.getInstance(reactContext).enqueue(periodicWorkRequest); } }
Is it possible to trigger headless task everything 5 or 10 seconds or every 10 or 50m distance?
with workers the minimum time for re-run is 15 minutes
@felansu Thanks I will try
I've updated the example project to show how to use foreground service with location, see if it helps you. You can find the relevant changes in this commit https://github.com/Agontuk/react-native-geolocation-service/commit/cb7b98ead8c3bde21071b256f36ff7644c5e376a.
For someone still facing this. Make sure you've added ACCESS_BACKGROUND_LOCATION in your androidmanifest. and ask for it in app permissions.
@felansu @lyseiha Hey Iam unable to get it working. Where should be the headless task registered? In app.js or in any js file where I want to track. And is the java code provided in this thread should be included in react native app code as well or not. If yes where. And is there any workaround for tracking location every 3 or 5 mins. And Iam looking for a solution that works even when phone is locked or app is in background or killed or open. please anyone who knows any of these, try to address my concerns. Thanks
Where should be the headless task registered?
yes
@felansu I didnt get it. There are few questions in asked by me @vijay13267. Could you pls answers for each of them seperately if you dont mind. Thanks
Are these files required in react native project too?
If Yes, where to write them. in which path?
Thanks
@Vijay-CareAllianz all i know 4 years ago is answered and published in this thread, today i don't use that dependency and as you understand I don't remember much about this, it has rained a lot since then, good luck