Open williamFportillo opened 1 week ago
One thing I noticed in the documentation is that the schedule property receives an array. However, in the logs, the schedule property is using () for the array.
This is nothing to worry about. This is merely how an Obj-c NSArray#as_string
method prints its contents to the logs.
I share with you the full logs background-geolocation.log-15.gz
@christocracy
Are you absolutely sure that your app is calling .ready(config) each time your app is launched, no matter what — even if your app is automatically launched by the OS in the background?
import { AppRegistry } from 'react-native';
import BackgroundGeolocation from 'react-native-background-geolocation';
import App from './App';
AppRegistry.registerComponent(appName, () => App);
BackgroundGeolocation.registerHeadlessTask(HeadlessTask);
In my App.tsx
exist a global component <Geolocator />
and this component execute once a function that i use to do BackgroundGeolocation.ready
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import ErrorBoundary from './src/ErrorBoundary';
import Geolocator from '.src/Geolocator';
const App = () => (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<ErrorBoundary>
<Geolocator />
<MainStack /> {/* Handle my screens views */}
</ErrorBoundary>
</PersistGate>
</Provider>
);
export default App;
In this component i use a custom hook related with all the backgroungGeolocation functionality.
geolocatorConfig()
execute BackgroundGeolocation.ready()
import { useEffect } from 'react';
import { useBackgroundGeolocation } from '@hooks';
const Geolocator = () => {
const { geolocatorConfig } = useBackgroundGeolocation();
useEffect(() => {
/*
ℹ️ The function that executes the BackgroundGeolocation.ready()
I think is called each time the app is launched, but I'm not sure
if it is because that is inside of this useEffect is prevented from being executed,
and I have to take it away from here.
*/
geolocatorConfig();
}, []);
return <></>;
};
export default Geolocator;
geolocatorConfig
execute BackgroundGeolocation.ready
and this contain my current configuration.startGeolocation
function start the plug-in.stopGeolocation
function stop the plug-in,configureSchedule
execute a reset of the schedule and make a BackgroundGeolocation.setConfig
to set the new schedule. This function also evaluate if is neccesary start the plug-in again.
import BackgroundGeolocation, { Location, State } from 'react-native-background-geolocation';
import { useAppDispatch, useAppSelector } from './useRedux.hook';
} export const useBackgroundGeolocation = () => { const dispatch = useAppDispatch(); const geolocatorSettings = useAppSelector((state) => state.geolocator.geolocatorSettings); const isTrackingAlways = useAppSelector((state) => state.geolocator.trackingAlways); const toggleStatus = useAppSelector((state) => state.geolocator.toggleStatus);
const geolocatorConfig = (
config: GeolocatorConfig = { userIdParam: undefined, sessionId: '' },
) => {
const { userIdParam, sessionId } = config;
// ℹ️ Here I'm calling the method .ready() from the plugin
BackgroundGeolocation.ready({
desiredAccuracy: geolocatorSettings.desiredAccuracy,
distanceFilter: geolocatorSettings.distanceFilter,
stopTimeout: geolocatorSettings.stopTimeOut,
debug: false,
logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
logMaxDays: 4,
stopOnTerminate: geolocatorSettings.stopOnTerminate,
startOnBoot: true,
url: ${API_URL}/v2/location/${userIdParam || userId}
,
showsBackgroundLocationIndicator: true,
disableLocationAuthorizationAlert: true,
maxDaysToPersist: 5,
maxRecordsToPersist: -1,
heartbeatInterval: 60 geolocatorSettings.heartBeatInterval,
preventSuspend: true,
foregroundService: true,
disableElasticity: geolocatorSettings.disableElasticity,
elasticityMultiplier: geolocatorSettings.elasticityMultiplier,
stopOnStationary: geolocatorSettings.stopOnStationary,
disableMotionActivityUpdates:
geolocatorSettings.disableMotionActivityUpdates,
disableProviderChangeRecord: false,
allowIdenticalLocations: geolocatorSettings.allowIdenticalLocations,
locationUpdateInterval: geolocatorSettings.locationUpdateInterval 1000,
fastestLocationUpdateInterval:
1000 * geolocatorSettings.fastestLocationUpdateInterval,
enableHeadless: true,
locationsOrderDirection: 'ASC',
headers: {
'x-app-secret': envVariables.APP_SECRET_HEADER,
},
extras: {
sessionId: sessionId || uniqueId,
os: Platform.OS === 'ios' ? 'ios' : 'android',
},
locationAuthorizationRequest: 'Always',
scheduleUseAlarmManager: true,
stationaryRadius: 250,
isMoving: true,
activityType: BackgroundGeolocation.ACTIVITY_TYPE_OTHER,
backgroundPermissionRationale: {
title: translate('backgroundPermissionRationaleTitle'),
message: translate('backgroundPermissionRationaleMessage'),
positiveAction: translate('backgroundPermissionRationalePositiveAction'),
negativeAction: translate('cancel'),
},
}).catch();
};
const stopGeolocation = (navigateTo?: () => void) => { BackgroundGeolocation.getCurrentPosition({ timeout: 30, maximumAge: 5000, desiredAccuracy: 10, }).then((position) => { const lastPosition = { ...position, event: 'gps_off', }; sendLocations(lastPosition); }); dispatch(changeToggleStatus(false)); BackgroundGeolocation.stopSchedule(); BackgroundGeolocation.stop(); BackgroundGeolocation.destroyLocations(); BackgroundGeolocation.removeListeners(); navigateTo?.(); };
const initBackgroundGeolocation = async () => { const location = await BackgroundGeolocation.getCurrentPosition({ timeout: 30, maximumAge: 5000, desiredAccuracy: 10, }); const firstPosition = { ...location, event: 'gps_on', }; sendLocations(firstPosition); };
const startGeolocation = async (cb?: () => void) => { if (isTrackingAlways) { await BackgroundGeolocation.start(); } else { await BackgroundGeolocation.startSchedule(); } initBackgroundGeolocation(); dispatch(changeToggleStatus(true)); cb?.(); };
const resetSchedule = async (workdays?: Workdays): Promise
// ℹ️ This function is called when the user change the schedule on the app
const configureSchedule = async ({
workdays, isTrackingAlwaysActive = isTrackingAlways,
}): Promise
if (toggleStatus && !isTrackingAlwaysActive) {
await BackgroundGeolocation.startSchedule();
}
} catch (error) {
// error
}
};
return { stopGeolocation, geolocatorConfig, startGeolocation, getGeolocatorState, saveGeolocatorConfigOnDb, resetSchedule, configureSchedule, isSavingGeolocatorConfig: loading, }; };
---
## Login.tsx
When i do login i call `geolocatorConfig` to set in `BackgroundGeolocation.ready({})` a config with the values of the user.
```tsx
import React, { useEffect, useRef, useState } from 'react';
import { useAppDispatch, useAppSelector, useBackgroundGeolocation, useTranslate } from '@hooks';
import { AxiosError } from 'axios';
export const Login = () => {
const dispatch = useAppDispatch();
const workdays = useAppSelector((state) => state.user.workdays);
const fcmToken = useAppSelector((state) => state.user.fcmToken);
const { geolocatorConfig } = useBackgroundGeolocation();
const { execute } = authService.login();
const validateSession = async (code: string): Promise<void> => {
try {
const result = await execute<LoginResponse>({
phoneNumber,
areaCode,
otp: code,
fcmToken,
phoneOS: DeviceInfo.getSystemName(),
phoneModel: DeviceInfo.getModel(),
});
if (result.status === 200) {
/* ℹ️ Here I'm calling the method .ready() from the plugin again,
Not sure if this may cause an issue, but I don't think it does
because the screen only appears once, and then should be called globally
in the `Geolocator` component
*/
geolocatorConfig({
userIdParam: result.data?.id,
sessionId: result.data?.uniqueId!,
});
}
} catch (err) {
showAlert();
}
};
return (<></>);
};
@christocracy This is how I am setting up the plug-in
It’s a yes or no question. It’s not for me to analyze your code.
Are you absolutely sure that your app is calling .ready(config) each time your app is launched, no matter what — even if your app is automatically launched by the OS in the background?
const Geolocator = () => {
const { geolocatorConfig } = useBackgroundGeolocation();
useEffect(() => {
/*
ℹ️ The function that executes the BackgroundGeolocation.ready()
*/
geolocatorConfig(); // BackgroundGeolocation.ready({ config }) 👈🏻
}, []);
return <></>;
};
const App = () => (
<Geolocator />
);
export default App;
Your Environment
react-native -v
): 0.72.6Expected Behavior
When a schedule is configured and the plug-in is started that schedule will always be running.
Actual Behavior
When a schedule is configured and the plug-in is initialized it starts working as expected. But sometimes after a certain number of days or even hours the schedule stops working. It seems that it does not detect positions or something like that.
To set up a schedule I am currently doing this:
Steps to Reproduce
Context
Wednesday, 26 June
The schedule was set up and worked as expected, tracking the day from 00:00 to 18:00.
As you can see, the tracking service stopped sending the location at 17:59:34 to the server. The user continued moving but was out of schedule, this behavior is expected. On the map, you can see an image with the information of the last position sent to the server.
Thursday, 27 June
The user continued moving, but none of the positions were sent to the server, and we are unable to see them in the logs as well. The last thing we saw on the logs was something related to geofences but we are not using the functionality (just in case).
One thing I noticed in the documentation is that the schedule property receives an array. However, in the logs, the schedule property is using () for the array. Thats something is just happening on iOS and it could just be how the log is being printed, but I thought I'd mention it in case it helps you as well.
Debug logs
Logs
I share with you the logs file because is too large. ![Screenshot 2024-06-28 at 12 22 04 PM](https://github.com/transistorsoft/react-native-background-geolocation/assets/17710256/bbd14a79-54a2-40e2-bce3-3a48f26f0b94) [background-geolocation.log-14.gz](https://github.com/user-attachments/files/16034667/background-geolocation.log-14.gz)