transistorsoft / capacitor-background-geolocation

The most sophisticated background location-tracking & geofencing module with battery-conscious motion-detection intelligence for iOS and Android.
MIT License
97 stars 16 forks source link

Scheduler Fails to Start On iOS #99

Closed brian-weasner closed 1 year ago

brian-weasner commented 2 years ago

Your Environment

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! 👌

* Plugin config provided to `#ready`:
```javascript
/**
   * This is the config for the TransistorSoft Background Geolocation.
   * On **First Install** and use this is the value that gets set within the plugin.
   * On **Subsequent Launches** of the app, this will override configuration (for the properties with values provided) that was set on first use.
   *
   * @type {Config}
   * @private
   */
  private readonly INIT_CONFIG: Config = {
    // Plugin Config
    reset: false,                  // <-- Setting to false allows the BackgroundGeolocation to re-apply its persisted configuration (Makes it not clear out schedule and other config data when ready is called). We handle updating the config with the values set in INIT_CONFIG after ready. So that if INIT_CONFIG values change, the config is set without resetting peristed values.
    // Location Settings
    desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
    distanceFilter: 10,
    // Activity Recognition
    stopTimeout: 1,
    // Application config
    stopOnTerminate: false,        // <-- Setting to false allows the background-service to continue tracking when user closes the app.
    startOnBoot: true,             // <-- Auto start tracking when device is powered-up.
    foregroundService: true,       // <-- Help Android from killing the app if running
    // Schedule Tracking
    // schedule                    // <-- Do not set `schedule` property (even as undefined), so that on ready we do not overwrite any existing schedules from previous launch
    scheduleUseAlarmManager: true, // <-- Force the Android scheduler to use AlarmManager (more precise) instead of JobScheduler
    // HTTP / SQLite config
    batchSync: false,              // <-- [Default: false] Set true to sync locations to server in a single HTTP request.
    autoSync: true,                // <-- [Default: true] Set true to sync each location to server as it arrives.
    headers: {},                   // <-- HTTP Headers
    params: {},                    // <-- Optional HTTP params append to each HTTP request
    extras: {},                    // <-- Optional meta-data appended to each recorded location.
    maxDaysToPersist: 3,           // <-- Maximum number of days to persist offline/unsuccessfully sent location data
    // Location Notification
    notification: {
      channelName: 'Driver Location Tracking',
      smallIcon: "drawable/location_notification_icon"
    },
    // Permissions
    backgroundPermissionRationale: {
      title: 'Location Services Required',
      message: `Enable location permission, and set to {backgroundPermissionOptionLabel}. This is required so that the app can track your location during a trip.`
    },
    // iOS will prompt for location permission we want.
    locationAuthorizationRequest: 'Always',
    disableLocationAuthorizationAlert: true // We handle routing the user to the settings page for both ios and android
  } as const; // as const allows the internal values to be unmodifiable as well.

Expected Behavior

  1. Set Schedule in config
    • Done by getting the current state, and updating the schedule field/property
    • Wait for promise to resolve
  2. Call startSchedule
    • Await for promise to resolve
  3. Check that the returned state from the resolved startSchedule call actually enabled the scheduler.
  4. Should Succeed Every Time

Actual Behavior

  1. Set Schedule in config
    • Done by getting the current state, and updating the schedule field/property
    • Wait for promise to resolve
  2. Call startSchedule
    • Await for promise to resolve
  3. Check that the returned state from the resolved startSchedule call actually enabled the scheduler.
  4. Difference: schedulerEnabled is false!

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)
christocracy commented 2 years ago

You're doing something wrong. Show me your code.

christocracy commented 2 years ago

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.

brian-weasner commented 2 years ago

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.

brian-weasner commented 2 years ago

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()

Code:

  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.

christocracy commented 2 years ago

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.

brian-weasner commented 2 years ago

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?

christocracy commented 2 years ago

The scheduler can become disabled if you call .stopSchedule() or provide it with an empty schedule: []

brian-weasner commented 2 years ago

That should be fine as our code handles everything with async await due to your library properly returning promises.

  1. Clear Schedule (function call)
    1. get config
    2. clear schedule
    3. set config
    4. From what you have said can set scheduler to disabled (which is fine at this point)
  2. Add Schedule Item (function call)
    1. get config
    2. add schedule
    3. set config
  3. Start Schedule (function call)
    1. get state
    2. if state.schedulerEnabled is false
      1. start schedule
      2. get config/state from resolve startSchedule promise
      3. state.schedulerEnabled should be true, but isn't ################## This is the part that is failing.

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

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
}
christocracy commented 2 years ago

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);
    }
  }
Screen Shot 2022-09-28 at 10 43 03 AM
christocracy commented 2 years ago

I'm using version 4.8.3

I suggest you test with latest version.

brian-weasner commented 2 years ago

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.

brian-weasner commented 2 years ago

Hi Chris,

Just wanted to send an update about this issue.

  1. We are still seeing the errors happening intermittently on ios 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.

  1. I will be creating a new ticket for documentation improvements. - as the 400 http request errors happening around the same time as the scheduler failing to start has been deemed unrelated.

Thank you, ~ Brian

brian-weasner commented 1 year ago

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

💊   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! 👌

Dependencies

"@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

christocracy commented 1 year ago

in the changelog, do you think the fix could solve my issue?

I doubt it.

brian-weasner commented 1 year ago

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

Expected Behavior

  1. Clear Schedule in config
    • Done by getting the current state, and updating the schedule field/property
    • Wait for promise to resolve
  2. Set Schedule in config (for now till 3min in the future)
    • Done by getting the current state, and updating the schedule field/property
    • Wait for promise to resolve
  3. Call startSchedule
    • Await for promise to resolve
    • Check that the returned state from the resolved startSchedule call actually enabled the scheduler.
    • Should Succeed Every Time
  4. DO STEPS 1-3 AGAIN! (within the 3 min of the schedule)
    • This is something that happens if the state of our application changes and we need to recalculate the geolocation schedule.
    • We handle the 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?)

Actual Behavior

  1. Clear Schedule in config
    • Done by getting the current state, and updating the schedule field/property
    • Wait for promise to resolve
  2. Set Schedule in config (for now till 3min in the future)
    • Done by getting the current state, and updating the schedule field/property
    • Wait for promise to resolve
  3. Call startSchedule
    • Await for promise to resolve
    • Check that the returned state from the resolved startSchedule call actually enabled the scheduler.
    • Will Succeed the first time
  4. DO STEPS 1-3 AGAIN! (within the 3 min of the schedule)
    • Checking the returned state from the resolved startSchedule call shows that enabled = true, but schedulerEnabled = false.
    • After this, any call to startSchedule will never set schedulerEnabled to true, even if the schedule is cleared and stopSchedule and then stop is called

Debug Logs (Newest -> Oldest)

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.

brian-weasner commented 1 year ago

@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.

christocracy commented 1 year ago

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!
brian-weasner commented 1 year ago

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!

Code Referenced above

  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;
    }
  }
christocracy commented 1 year ago

Go ahead and create a simple Hello World app that reproduces this. Share the Github repo here.

brian-weasner commented 1 year ago

Will do.

brian-weasner commented 1 year ago

Hey Chris,

Repo

Simple App with issue reproduction here: https://github.com/brian-weasner/cap-background-geolocation-error-reproduction

Notes:

Steps to Reproduce

  1. Click Track for Next 3 minutes
  2. Click Start Schedule
  3. Click Clear Schedule
  4. Do steps 1-3
  5. See that Step 3 failed
brian-weasner commented 1 year ago

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.

brian-weasner commented 1 year ago

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

christocracy commented 1 year ago

I've reproduced this and discovered the problem.

Fix is released to 4.11.2

brian-weasner commented 1 year ago

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!

christocracy commented 1 year ago

Great, thanks for letting me know.