react-native-background-geolocation
react-native-background-geolocation copied to clipboard
Can't get userLocation to update consistently in background mode
Your Environment
- Plugin version:4.11.0
- Platform: iOS or Android: ios
- OS version: 16.4
- Device manufacturer / model: iphone 13
- React Native version (
react-native -v): 0.70.6 - Plugin config
export default class FGLocationRetriever {
static instance = null;
static getInstance() {
if (this.instance == null) {
this.instance = new FGLocationRetriever();
}
return this.instance;
}
constructor() {
this.userKey = null;
this.keysToTrack = [];
this.keyToPhone = {};
this.allowedKeysToTrackMe = [];
this._onTick = this._onTick.bind(this);
this._onUserLocationChange = this._onUserLocationChange.bind(this);
this.intervalHandler = null;
this.initialized = false;
}
init() {
this.userKey = null;
this.keysToTrack = [];
this.keyToPhone = {};
this.allowedKeysToTrackMe = [];
this.intervalHandler = null;
this.locationTrackingOn = false;
if (!this.initialized) {
FGLocationTrackingService.getInstance().init();
FGLocationTrackingService.getInstance().setOnLocationListener(
this._onUserLocationChange
);
}
this._loadDataLocaly();
this.initialized = true;
}
async _saveDataLocaly() {
const data = {
userKey: this.userKey,
keysToTrack: this.keysToTrack,
allowedKeysToTrackMe: this.allowedKeysToTrackMe,
keyToPhone: this.keyToPhone,
locationTrackingOn: this.locationTrackingOn,
};
await AsyncStorage.setItem("FGLocationRetriever", JSON.stringify(data));
}
async _loadDataLocaly() {
const data = await AsyncStorage.getItem("FGLocationRetriever");
if (data) {
const parsedData = JSON.parse(data);
this.userKey = parsedData.userKey;
this.keysToTrack = parsedData.keysToTrack;
this.allowedKeysToTrackMe = parsedData.allowedKeysToTrackMe;
this.keyToPhone = parsedData.keyToPhone;
if (parsedData.locationTrackingOn) {
this.startLocationTracking();
} else if (!parsedData.locationTrackingOn) {
this.stopLocationTracking();
}
}
}
async _removeDataLocaly() {
await AsyncStorage.removeItem("FGLocationRetriever");
}
async setUserPhone(phone) {
this.userKey = await this._getUserKey(phone);
await this._saveDataLocaly();
}
_onUserLocationChange(location) {
try {
database()
.ref(`locations/${this.userKey}`)
.set({
lat: location.latitude,
long: location.longitude,
date: moment().format("YYYY-MM-DD HH:mm:ss"),
})
} catch (error) {
console.log(error);
}
}
startLocationTracking() {
FGLocationTrackingService.getInstance().startLocationTracking();
this.locationTrackingOn = true;
let ref = database().ref(`permissions/${this.userKey}`);
ref.set(this.allowedKeysToTrackMe);
this._saveDataLocaly();
}
stopLocationTracking() {
FGLocationTrackingService.getInstance().stopLocationTracking();
this.locationTrackingOn = false;
let ref = database().ref(`permissions/${this.userKey}`);
ref.set([]);
this._saveDataLocaly();
}
async _onTick() {
if (!this.locationTrackingOn) {
this.onPhonesLocationsListener([]);
return;
}
let locations = [];
await Promise.all(
this.keysToTrack.map(async (key) => {
const ref = database().ref(`permissions/${key}`);
const permissions = await ref.once("value");
if (
permissions.exists() &&
(permissions.val().includes(this.userKey) || "*" in permissions)
) {
const ref = database().ref(`locations/${key}`);
const user = await ref.once("value");
console.log(this.keyToPhone[key])
if (user.exists() && this.keyToPhone[key]) {
const userModel = user.val();
userModel["phone"] = this.keyToPhone[key];
locations = [...locations, userModel]
}
}
})
);
if (this.onPhonesLocationsListener) {
this.onPhonesLocationsListener(locations);
}
}
startListeningToLocationUpdates() {
if (this.intervalHandler != null) {
clearInterval(this.intervalHandler);
}
this.intervalHandler = setInterval(this._onTick, 10000);
}
stopListeningToLocationUpdates() {
clearInterval(this.intervalHandler);
this.intervalHandler = null;
}
setPhonesToTrack(phones) {
this.keysToTrack = Promise.all(phones.map(async (phone) => await this._getUserKey(phone)));
this._saveDataLocaly();
}
async addPhoneToTrack(phone) {
const key = await this._getUserKey(phone);
if (!this.keysToTrack.includes(key)) {
this.keysToTrack = [...this.keysToTrack, key];
}
this._saveDataLocaly();
}
async removePhoneToTrack(phone) {
const key = await this._getUserKey(phone);
if (this.keysToTrack.includes(key)) {
this.keysToTrack = this.keysToTrack.filter((k) => k != key);
}
this._saveDataLocaly();
}
async reset() {
await this._removeDataLocaly();
this.init();
}
setOnPhonesLocationsListener(listener) {
this.onPhonesLocationsListener = listener;
}
async allowPhonesToTrackMe(phones) {
this.allowedKeysToTrackMe = await Promise.all(
phones.map(async (phone) => await this._getUserKey(phone))
);
let ref = database().ref(`permissions/${this.userKey}`);
const hashes = this.allowedKeysToTrackMe;
ref.set(hashes);
this._saveDataLocaly();
}
async allowPhoneToTrackMe(phone) {
const key = await this._getUserKey(phone);
if (!this.allowedKeysToTrackMe.includes(key)) {
this.allowedKeysToTrackMe = [...this.allowedKeysToTrackMe, key];
}
let ref = database().ref(`permissions/${this.userKey}`);
const hashes = this.allowedKeysToTrackMe;
ref.set(hashes);
this._saveDataLocaly();
}
async disallowPhoneToTrackMe(phone) {
const key = await this._getUserKey(phone);
if (this.allowedKeysToTrackMe.includes(key)) {
this.allowedKeysToTrackMe = this.allowedKeysToTrackMe.filter(
(k) => k != key
);
let ref = database().ref(`permissions/${this.userKey}`);
const hashes = this.allowedKeysToTrackMe;
ref.set(hashes);
}
this._saveDataLocaly();
}
async _getUserKey(phone) {
if (phone == "*") {
return "*";
}
const numeric_string = phone.replace(/\D/g,'');
console.log(phone);
console.log(numeric_string);
const key = await sha1(numeric_string.substring(numeric_string.length - 7));
console.log(key)
this.keyToPhone[key] = phone;
return key;
}
}
Expected Behavior
Contacts locations should update automatically every 10 seconds automatically
Actual Behavior
contacts location does not update very often
Steps to Reproduce
Context
trying to make a find my friends clone app
Debug logs
Logs
PASTE_YOUR_LOGS_HERE
Your code doesn't contain any reference to the BackgroundGeolocation plugin.
whoops,
import BackgroundGeolocation, {
Location,
Subscription,
} from "react-native-background-geolocation";
export default class FGLocationTrackingService {
static instance = null;
static getInstance() {
if (this.instance == null) {
this.instance = new FGLocationTrackingService();
}
return this.instance;
}
constructor() {
this.permissionGranted = false;
this._BGonHeartbeat = this._BGonHeartbeat.bind(this);
}
setOnLocationListener(listener) {
this.onLocationListener = listener;
}
init() {
BackgroundGeolocation.onLocation(this._BGonLocation);
BackgroundGeolocation.onHeartbeat(this._BGonHeartbeat);
BackgroundGeolocation.ready({
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
heartbeatInterval: 60,
preventSuspend: true,
stopTimeout: 5,
debug: false,
logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
stopOnTerminate: false,
startOnBoot: true,
batchSync: false,
autoSync: true,
}).then((state) => {
console.log(
"- BackgroundGeolocation is configured and ready: ",
state.enabled
);
});
}
_BGonHeartbeat(event) {
console.log("[onHeartbeat]", event.location.coords);
if (this.onLocationListener) this.onLocationListener(event.location.coords);
}
_BGonLocation(event) {
console.log("[onLocation]", event.coords);
}
_onLocationPermissionGranted() {
this.permissionGranted = true;
}
_onLocationPermissionDenied() {
this.permissionGranted = false;
}
requestTrackingPermission() {
BackgroundGeolocation.requestPermission(
this._onLocationPermissionGranted,
this._onLocationPermissionDenied
);
}
startLocationTracking() {
BackgroundGeolocation.start(
this._onLocationPermissionGranted,
this._onLocationPermissionDenied
);
}
stopLocationTracking() {
BackgroundGeolocation.stop();
}
}
// requestTrackingPermission() {
// Permissions.request(PERMISSIONS.IOS.LOCATION_ALWAYS).then(response => {
// console.log(response);
// if (response == "granted") {
// this.permissionGranted = true;
// } else {
// this.permissionGranted = false;
// }
// });
// }
// trackLocation() {
// GetLocation.getCurrentPosition({
// enableHighAccuracy: true,
// timeout: 60000,
// })
// .then(location => {
// console.log(location);
// })
// .catch(error => {
// const { code, message } = error;
// console.warn(code, message);
// console.log("WTFFFFF")
// })
// }
// stopLocationTracking() {
// BackgroundTimer.stopBackgroundTimer();
// }
// async sendDataToFirebase(location) {
// // key is last 8 digits of phone number with sha1 hash
// const key = Crypto.createHash('sha256')
// .update(this.phoneNumber.substring(this.phoneNumber.length - 8))
// .digest('hex')
// console.log(key);
// // get sha1 of key
// //const reference = database().ref('/users/'+);
// }
// async startLocationTracking() {
// console.log("startLocationTracking");
// if (!this.permissionGranted) {
// console.log("startLocationTracking: permission not granted");
// this.requestTrackingPermission();
// return;
// }
// this.sendDataToFirebase(undefined);
// console.log("startLocationTracking: permission granted");
// const onLocation = BackgroundGeolocation.onLocation((location) => {
// console.log('[onLocation]', location.coords);
// });
// BackgroundGeolocation.onHeartbeat((event) => {
// console.log('[onHeartbeat]', event.location.coords);
// });
// BackgroundGeolocation.ready({
// // Geolocation Config
// desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
// distanceFilter: 0,
// heartbeatInterval: 10,
// disableElasticity: true,
// preventSuspend: true,
// // Activity Recognition
// stopTimeout: 5,
// // Application config
// debug: false, // <-- enable this hear sounds for background-geolocation life-cycle.
// logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
// stopOnTerminate: true, // <-- Allow the background-service to continue tracking when user closes the app.
// startOnBoot: true, // <-- Auto start tracking when device is powered-up.
// batchSync: false, // <-- [Default: false] Set true to sync locations to server in a single HTTP request.
// autoSync: false, // <-- [Default: true] Set true to sync each location to server as it arrives.
// }).then((state) => {
// console.log("- BackgroundGeolocation is configured and ready: ", state.enabled);
// });
// BackgroundGeolocation.start();
// }
// }
Show me evidence of this behaviour with a screenshot of tracking on a map.

The light blue dot is my currentLocation and the dark blue dot is my stores location in Db. My dark blue dot won't update in the background or in foreground unless I log out and log back in.
Are you testing in the iOS Simulator with "Freeway Drive" and observing the plugin logs in XCode?
No I am testing on my device with a TestFlight version
Have you tried installing the "Demo app" (linked in the README) to compare performance with your own app?
I suggest you boot your app in XCode Simulator and simulate location with Freeway Drive.
Okay I'll try this
Can you remind me what freeway drive is? Is it a location simulator?
Here's what the demo app looks like after one week. It's been tracking like this for the last 8 years, wherever I go in the world.
Simulating with Freeway Drive
debug: false,
Set it true so you can hear and see what the plug-in is doing
Should the auto sync prop be set to true or false?
Should the auto sync prop be set to true or false?
You aren’t providing the plug-in an url so autoSync is meaningless. How can the plug-in “automatically sync” (ie upload locations) when you’re not providing an url to upload to?
can we autosync with a firebase backend?
If you install the plug-in’s optional Firebase adapter, yes (Uses Firestore only)
https://github.com/transistorsoft/react-native-background-geolocation-firebase
otherwise, you must manage your own Firebase sync with you own JavaScript code.
thank you for your help, we will work on this today and update you with progress
Hey @jmcelroy99 have you had any luck?
This issue is stale because it has been open for 30 days with no activity.
This issue was closed because it has been inactive for 14 days since being marked as stale.