Closed brian-weasner closed 1 year ago
You're doing something wrong. Show me your code.
reset: false,
Do you know what this does? 99% of use-cases don't use reset: false
. If you don't know what reset
does, delete that from you config.
Yes.
According to the docs here: https://transistorsoft.github.io/capacitor-background-geolocation/interfaces/config.html#reset
if reset
is set to false, the plugin will re-apply its persisted configuration which was set by a previous instance of our app and ignore the config {}
supplied to the #ready
method.
ready
is expected, we call ready on app initialization, but we should never have any changes to the current config of the background geolocation plugin as we do not want our schedule in the config to be overwritten.
setConfig
function to be called. We do this in a couple places after the plugin has completed it's invocation of ready
I don't believe our code is wrong, as it works for all of our Android devices and Most of our Ios Devices. If this was an implementation issue we would be seeing this issue across all devices. However I understand that I'm a developer and that I frequently make mistakes.
Below is some of our code that directly relates to the issue we are having.
Please note that the log provided in the initial issue comment is a representation of function calls to this.log()
private async initialize(): Promise<void> {
this.log(`Initialize called`);
try {
// Initial Config Setup
const config: Config = {
...this.INIT_CONFIG, // Create from INIT_CONFIG Value
url: this.mobileConfig.backgroundGeolocation.apiEndpoint,
debug: this.mobileConfig.backgroundGeolocation.debug && this.environment.configuration !== EnvironmentConfiguration.Production,
logLevel: this.mobileConfig.backgroundGeolocation.debug ? BackgroundGeolocation.LOG_LEVEL_VERBOSE : BackgroundGeolocation.LOG_LEVEL_WARNING,
authorization: this.getAuthorizationConfig()
};
// Call Background Geolocation Ready Fn. (SHOULD ONLY BE CALLED ONCE PER APP!)
// Call setConfig if you need to change the configuration after ready has been called.
this.log(`Initialize => Make Ready`);
const readyState = await BackgroundGeolocation.ready(config);
// Do not log Authorization to debug log
this.log(`Initialized Background Geolocation Plugin, State On Ready: ${JSON.stringify({
...readyState,
authorization: undefined
})}`);
this.log(`Updating Config with set values from INIT_CONFIG`);
const afterInitConfigOverrides = await BackgroundGeolocation.setConfig({
...readyState,
...config
});
// Do not log Authorization to debug log
this.log(`Config Updated with INIT_CONFIG values: ${JSON.stringify({
...afterInitConfigOverrides,
authorization: undefined
})}`);
this.updateConfigOnJwtChanges(); // Only want to start listening after ready has been called.
} catch (error) {
this.log(`Initialize => Errored: ${error.toString()}`);
throw error;
}
}
public async addScheduleItem(scheduleItem: BackgroundGeolocationScheduleItemInterface): Promise<BackgroundGeolocationSchedule> {
this.log(`Add Schedule Called`);
await this.initializePromise;
try {
const newSchedule = this.getScheduleItemAsString(scheduleItem);
let currentConfig = await BackgroundGeolocation.getState(); // State extends Config.
currentConfig.schedule = [
...(currentConfig.schedule ?? []),
newSchedule
];
this.log(`Add Schedule => Adding: "${newSchedule}"`);
currentConfig = await BackgroundGeolocation.setConfig(currentConfig);
const schedule = this.getScheduleFromConfig(currentConfig);
this.scheduleChange.next(schedule);
return schedule;
} catch (error) {
this.log(`Add Schedule => Errored : ${error.message}`);
throw error;
}
}
public async startSchedule(): Promise<void> {
this.log(`Start Schedule Called`);
await this.initializePromise;
try {
let state = await BackgroundGeolocation.getState();
if (!state.schedulerEnabled) {
// Do not log Authorization to debug log
this.log(`Starting Schedule. Current State: ${JSON.stringify({...state, authorization: undefined})}`);
state = await BackgroundGeolocation.startSchedule();
// Do not log Authorization to debug log
this.log(`Schedule Started. Current State: ${JSON.stringify({...state, authorization: undefined})}`);
if (!state.schedulerEnabled) {
// Get logs from 4 min ago till now.
const backgroundGeolocationLogs = await BackgroundGeolocation.logger.getLog({
start: new Date().getTime() - (5 * 60 * 1_000),
end: new Date().getTime()
});
// Want this logged every time as we are currently having issues with ios devices not starting the scheduler.
this.log(backgroundGeolocationLogs);
throw new Error('Scheduler Failed To Start');
}
}
} catch (error) {
this.log(`Start Schedule => Errored : ${error.message}`);
throw error;
}
}
Let me know if you see any problems with how we are handling the initialization logic, as that is what you were hinting at that could be incorrect.
Do you know that the iOS scheduler cannot use a timer to trigger schedule events?
the iOS scheduler relies on the device moving about 500 meters for the schedule to be evaluated.
Yes The docs say that When a schedule is provided on iOS, it will be evaluated in the following cases:
It is my understanding that scheduler can be enabled whenever, however when the scheduler actually evaluates the schedule to determine if the tracking needs to be enabled/disabled happens when the above stated cases occur.
So this shouldn't cause issue with the scheduler not becoming enabled?
The scheduler can become disabled if you call .stopSchedule() or provide it with an empty schedule: []
That should be fine as our code handles everything with async await due to your library properly returning promises.
Because all of the above happens async and we are awaiting every single request/response to your plugin from a singleton service then schedulerEnabled should always be true if the config contains a schedule when startSchedule is called. (Look in our debug logs to see the current state before and after the call to startSchedule)
Current state is the same in our logs for right before the call to BackgroundGeolocation.startSchedule
and after. See below formatted state object.
{
"logLevel":5,
"disableStopDetection":false,
"url":"removed",
"disableAutoSyncOnCellular":false,
"geofenceInitialTriggerEntry":true,
"desiredAccuracy":-1,
"debug":false,
"maxRecordsToPersist":-1,
"pausesLocationUpdatesAutomatically":true,
"desiredOdometerAccuracy":100,
"useSignificantChangesOnly":false,
"stationaryRadius":25,
"didLaunchInBackground":true,
"maxDaysToPersist":3,
"httpRootProperty":"location",
"isMoving":true,
"stopOnStationary":false,
"maxBatchSize":-1,
"isFirstBoot":false,
"enableTimestampMeta":false,
"autoSyncThreshold":0,
"geofenceTemplate":"",
"minimumActivityRecognitionConfidence":70,
"lastLocationAuthorizationStatus":3,
"locationAuthorizationRequest":"Always",
"disableLocationAuthorizationAlert":true,
"locationTemplate":"",
"enabled":true,
"batchSync":false,
"didRequestUpgradeLocationAuthorization":false,
"locationsOrderDirection":"ASC",
"trackingMode":1,
"distanceFilter":10,
"showsBackgroundLocationIndicator":false,
"stopAfterElapsedMinutes":-1,
"schedule":[
"2022-09-20-07:55 2022-09-20-23:59"
],
"schedulerEnabled":false,
"autoSync":true,
"stopDetectionDelay":0,
"iOSHasWarnedLocationServicesOff":false,
"stopOnTerminate":false,
"elasticityMultiplier":1,
"logMaxDays":3,
"heartbeatInterval":60,
"persistMode":2,
"locationTimeout":60,
"locationAuthorizationAlert":{
"titleWhenOff":"Location services are off",
"settingsButton":"Settings",
"instructions":"To use background location, you must enable '{locationAuthorizationRequest}' in the Location Services settings",
"cancelButton":"Cancel",
"titleWhenNotEnabled":"Background location is not enabled"
},
"extras":{
},
"method":"POST",
"preventSuspend":false,
"startOnBoot":true,
"stopTimeout":1,
"activityRecognitionInterval":10000,
"odometer":3215618.3641011217,
"headers":{
},
"disableMotionActivityUpdates":false,
"geofenceProximityRadius":2000,
"params":{
},
"disableElasticity":false,
"activityType":1,
"didDeviceReboot":true,
"httpTimeout":60000
}
I cannot reproduce any problem with State.schedulerEnabled
using a simple test-case.
const onToggleEnabled = async () => {
let state = await BackgroundGeolocation.getState();
console.log('*** [onToggleEnabled] State.schedulerEnabled? ', state.schedulerEnabled);
if (enabled) {
await BackgroundGeolocation.setConfig({
schedule: ['1-7 09:00-17:00']
});
state = await BackgroundGeolocation.startSchedule();
console.log('*** [startSchedule] State.scheduleEnabled? ', state.schedulerEnabled);
} else {
await BackgroundGeolocation.stop();
state = await BackgroundGeolocation.stopSchedule();
console.log('*** [stopSchedule] State.scheduleEnabled? ', state.schedulerEnabled);
}
}
I'm using version 4.8.3
I suggest you test with latest version.
I'll update our app to use the latest and report to you about it sometime next week as I'll have to collect more logs from users experiencing the issue after we update.
I'll also get you more concrete data as to what value(s) we are getting that is not in line with the Activity Motion Event type and throwing validation errors on our server.
Hi Chris,
Just wanted to send an update about this issue.
15.5
, 15.6.1
, 15.7
, 16.0
, 16.0.2
with
@transistorsoft/capacitor-background-fetch
: 0.0.6
@transistorsoft/capacitor-background-geolocation
: 4.8.3
Please let me know if there is any more debugging or information that you require to help us solve this issue.
Thank you, ~ Brian
Hi Chris,
Just wanted to send another update about this issue.
I've updated our application within the last month to use Capacitor v4.
💊 Capacitor Doctor 💊
Latest Dependencies:
@capacitor/cli: 4.5.0
@capacitor/core: 4.5.0
@capacitor/android: 4.5.0
@capacitor/ios: 4.5.0
Installed Dependencies:
@capacitor/cli: 4.3.0
@capacitor/android: 4.3.0
@capacitor/core: 4.3.0
@capacitor/ios: 4.3.0
[success] iOS looking great! 👌
[success] Android looking great! 👌
"@transistorsoft/capacitor-background-fetch": "1.0.1",
"@transistorsoft/capacitor-background-geolocation": "4.9.0",
With these changes we are still seeing the errors happening intermittently on ios 15.5, 15.6.1, 15.7, 16.0, 16.0.2
I see that background-geolocation 4.9.1
has [iOS] Fix bug in iOS scheduler firing on days where it should not.
in the changelog, do you think the fix could solve my issue?
Please let me know if there is any more debugging or information that you require to help us solve this issue.
Thank you, ~ Brian
in the changelog, do you think the fix could solve my issue?
I doubt it.
I've finally gotten around to this ticket again and I've been able to reproduce on an ios 14 simulator.
Issue is not prevalent on Android, only iOS
stopSchedule
and stop
calls if we do not need to re-add an item to the schedule.NOTE: We do not always call stop and stopSchedule between schedule changes. (I don't believe this is necessary?)
Contains some TransistorSoft Logs (5 Minutes of logs before error -> Time of Error)
2023-03-07 Transistorsoft BgGeo error.log
Let me know if you need me to make a minimum reproducible project.
@christocracy Let me know if you need me to make a minimum reproducible project of the above comment, as it consistently breaks scheduled tracking on our iOS devices.
Do you know what these entries from your logs mean?
March 7, 2023 at 3:38:13 PM GMT-5: Background Geolocation: Clear Schedule Called (App ID: 2)
March 7, 2023 at 3:30:26 PM GMT-5: Background Geolocation: Start Schedule => Errored : Scheduler Failed To Start (App ID: 2)
2023-03-07 15:30:26.171 ⚠️-[TSScheduler start] Scheduler #start called with an empty schedule!
Yes!
March 7, 2023 at 3:38:13 PM GMT-5: Background Geolocation: Clear Schedule Called (App ID: 2)
March 7, 2023 at 3:30:26 PM GMT-5: Background Geolocation: Start Schedule => Errored : Scheduler Failed To Start (App ID: 2)
2023-03-07 15:30:26.171 ⚠️-[TSScheduler start] Scheduler #start called with an empty schedule!
public async clearSchedule(): Promise<BackgroundGeolocationSchedule> {
this.log(`Clear Schedule Called`);
await this.initializePromise;
try {
let currentConfig = await BackgroundGeolocation.getState(); // State extends Config.
if (currentConfig.schedule && currentConfig.schedule.length > 0) {
this.log(`Clearing Schedule`);
currentConfig.schedule = [];
currentConfig = await BackgroundGeolocation.setConfig(currentConfig);
const schedule = this.getScheduleFromConfig(currentConfig);
return schedule;
}
return this.getScheduleFromConfig(currentConfig);
} catch (error) {
this.log(`Clear Schedule => Errored : ${error.message}`);
throw error;
}
}
public async startSchedule(): Promise<void> {
this.log(`Start Schedule Called`);
await this.initializePromise;
try {
let state = await BackgroundGeolocation.getState();
if (!state.schedulerEnabled) {
// Do not log Authorization to debug log
this.log(`Starting Schedule. Current State: ${JSON.stringify({...state, authorization: undefined})}`);
state = await BackgroundGeolocation.startSchedule();
// Do not log Authorization to debug log
this.log(`Schedule Started. Current State: ${JSON.stringify({...state, authorization: undefined})}`);
if (!state.schedulerEnabled) {
// Get logs from 4 min ago till now.
const backgroundGeolocationLogs = await BackgroundGeolocation.logger.getLog({
start: new Date().getTime() - (5 * 60 * 1_000),
end: new Date().getTime()
});
// Want this logged every time as we are currently having issues with ios devices not starting the scheduler.
this.log(backgroundGeolocationLogs);
throw new Error('Scheduler Failed To Start');
}
}
} catch (error) {
this.log(`Start Schedule => Errored : ${error.message}`);
throw error;
}
}
Go ahead and create a simple Hello World app that reproduces this. Share the Github repo here.
Will do.
Hey Chris,
Simple App with issue reproduction here: https://github.com/brian-weasner/cap-background-geolocation-error-reproduction
Hello @christocracy,
Just wondering if you have had a chance to reproduce this issue in the hello world app I linked above?
Let me know if you need anything else.
Hey @christocracy,
I hate being that guy pinging you all the time, but this is still an issue. Please take a look at the hello world app reproduction I created.
Please let me know if you need anything. I'd like to get this resolved.
Thank you, -Brian
I've reproduced this and discovered the problem.
Fix is released to 4.11.2
This has been out in our production environment for some time now and we can confirm that the issue is fully resolved. Thank you so much for looking into and fixing this problem!
Great, thanks for letting me know.
Your Environment
4.4.3
iOS
15.6.1
,16.0
Apple iPhone
13.1
npx cap doctor
)Latest Dependencies:
@capacitor/cli: 4.3.0 @capacitor/core: 4.3.0 @capacitor/android: 4.3.0 @capacitor/ios: 4.3.0
Installed Dependencies:
@capacitor/cli: 3.1.2 @capacitor/core: 3.8.0 @capacitor/android: 3.1.2 @capacitor/ios: 3.1.2
[success] iOS looking great! 👌 [success] Android looking great! 👌
Expected Behavior
Actual Behavior
Context
Trying to set a schedule to include an item from the current date and time to today at 23:59 Local time and then start the scheduler.
This only ever fails on iOS, and does not fail every single time.
The times when this does fail, the transistorsoft logs show 400 request errors (from sending data to our server to save).
Debug logs
Our app logs right before failure (Newest -> Oldest)
``` (App ID: 195) September 20, 2022 at 7:55:08 AM GMT-4: Background Geolocation: Schedule Started. Current State: {"logLevel":5,"disableStopDetection":false,"url":"removed","disableAutoSyncOnCellular":false,"geofenceInitialTriggerEntry":true,"desiredAccuracy":-1,"debug":false,"maxRecordsToPersist":-1,"pausesLocationUpdatesAutomatically":true,"desiredOdometerAccuracy":100,"useSignificantChangesOnly":false,"stationaryRadius":25,"didLaunchInBackground":true,"maxDaysToPersist":3,"httpRootProperty":"location","isMoving":true,"stopOnStationary":false,"maxBatchSize":-1,"isFirstBoot":false,"enableTimestampMeta":false,"autoSyncThreshold":0,"geofenceTemplate":"","minimumActivityRecognitionConfidence":70,"lastLocationAuthorizationStatus":3,"locationAuthorizationRequest":"Always","disableLocationAuthorizationAlert":true,"locationTemplate":"","enabled":true,"batchSync":false,"didRequestUpgradeLocationAuthorization":false,"locationsOrderDirection":"ASC","trackingMode":1,"distanceFilter":10,"showsBackgroundLocationIndicator":false,"stopAfterElapsedMinutes":-1,"schedule":["2022-09-20-07:55 2022-09-20-23:59"],"schedulerEnabled":false,"autoSync":true,"stopDetectionDelay":0,"iOSHasWarnedLocationServicesOff":false,"stopOnTerminate":false,"elasticityMultiplier":1,"logMaxDays":3,"heartbeatInterval":60,"persistMode":2,"locationTimeout":60,"locationAuthorizationAlert":{"titleWhenOff":"Location services are off","settingsButton":"Settings","instructions":"To use background location, you must enable '{locationAuthorizationRequest}' in the Location Services settings","cancelButton":"Cancel","titleWhenNotEnabled":"Background location is not enabled"},"extras":{},"method":"POST","preventSuspend":false,"startOnBoot":true,"stopTimeout":1,"activityRecognitionInterval":10000,"odometer":3215618.3641011217,"headers":{},"disableMotionActivityUpdates":false,"geofenceProximityRadius":2000,"params":{},"disableElasticity":false,"activityType":1,"didDeviceReboot":true,"httpTimeout":60000} (App ID: 195) September 20, 2022 at 7:55:08 AM GMT-4: Background Geolocation: Starting Schedule. Current State: {"logLevel":5,"disableStopDetection":false,"url":"removed","disableAutoSyncOnCellular":false,"geofenceInitialTriggerEntry":true,"desiredAccuracy":-1,"debug":false,"maxRecordsToPersist":-1,"pausesLocationUpdatesAutomatically":true,"desiredOdometerAccuracy":100,"useSignificantChangesOnly":false,"stationaryRadius":25,"didLaunchInBackground":true,"maxDaysToPersist":3,"httpRootProperty":"location","isMoving":true,"stopOnStationary":false,"maxBatchSize":-1,"isFirstBoot":false,"enableTimestampMeta":false,"autoSyncThreshold":0,"geofenceTemplate":"","minimumActivityRecognitionConfidence":70,"lastLocationAuthorizationStatus":3,"locationAuthorizationRequest":"Always","disableLocationAuthorizationAlert":true,"locationTemplate":"","enabled":true,"batchSync":false,"didRequestUpgradeLocationAuthorization":false,"locationsOrderDirection":"ASC","trackingMode":1,"distanceFilter":10,"showsBackgroundLocationIndicator":false,"stopAfterElapsedMinutes":-1,"schedule":["2022-09-20-07:55 2022-09-20-23:59"],"schedulerEnabled":false,"autoSync":true,"stopDetectionDelay":0,"iOSHasWarnedLocationServicesOff":false,"stopOnTerminate":false,"elasticityMultiplier":1,"logMaxDays":3,"heartbeatInterval":60,"persistMode":2,"locationTimeout":60,"locationAuthorizationAlert":{"titleWhenOff":"Location services are off","settingsButton":"Settings","instructions":"To use background location, you must enable '{locationAuthorizationRequest}' in the Location Services settings","cancelButton":"Cancel","titleWhenNotEnabled":"Background location is not enabled"},"extras":{},"method":"POST","preventSuspend":false,"startOnBoot":true,"stopTimeout":1,"activityRecognitionInterval":10000,"odometer":3215618.3641011217,"headers":{},"disableMotionActivityUpdates":false,"geofenceProximityRadius":2000,"params":{},"disableElasticity":false,"activityType":1,"didDeviceReboot":true,"httpTimeout":60000} (App ID: 195) September 20, 2022 at 7:55:08 AM GMT-4: Background Geolocation: Start Schedule Called (App ID: 195) September 20, 2022 at 7:55:08 AM GMT-4: Background Geolocation: Add Schedule => Adding: "2022-09-20-07:55 2022-09-20-23:59" (App ID: 195) September 20, 2022 at 7:55:08 AM GMT-4: Background Geolocation: Add Schedule Called (App ID: 195) September 20, 2022 at 7:55:08 AM GMT-4: Background Geolocation: Clearing Schedule (App ID: 195) September 20, 2022 at 7:55:08 AM GMT-4: Background Geolocation: Clear Schedule Called (App ID: 195) ```TransistorSoft Logs (5 Minutes of logs before error -> Time of Error)
Please see attached file, as github didn't allow creation of the ticket with the logs inline (`Comment is too long (maximum is 65536 characters)`) [transistorsoft-bg-geolocation.log](https://github.com/transistorsoft/capacitor-background-geolocation/files/9649186/transistorsoft-bg-geolocation.log)