Skip to content

[Bug]: iOS onProviderChange in v5 does not fire when settings change, unlike in v4 #2559

@mwmcode

Description

@mwmcode

Required Reading

  • Confirmed

Plugin Version

5.1.1

Mobile operating-system(s)

  • iOS
  • Android

Device Manufacturer(s) and Model(s)

iphone 16 pro, ios simulator 17 pro

Device operating-systems(s)

iOS 26.4

React Native / Expo version

Expo 55

What happened?

  1. open my-app, grant permission (while using app, keep while using app)
  2. press home to exit the app
  3. open settings -> apps -> my-app -> location permission -> set to never

on v5.1.1, onLocation fires with error 1, onProviderChange does not fire.

on v4, onProviderChange fires as expected

minimal repo (main branch uses v5):

Plugin Code and/or Config

v5:
{
  // https://transistorsoft.github.io/react-native-background-geolocation/latest/interfaces/AppConfig.html
  app: {
    preventSuspend: false,
    stopOnTerminate: false,
    startOnBoot: true,
    enableHeadless: true,
    backgroundPermissionRationale: {
      title: 'Background rationale',
      message: 'my-app needs background location location',
      positiveAction: 'grant it',
      negativeAction: 'cancel',
    },
  },
  // https://transistorsoft.github.io/react-native-background-geolocation/latest/interfaces/GeoConfig.html
  geolocation: {
    locationAuthorizationRequest: 'Always',
    useSignificantChangesOnly: true,
    desiredAccuracy: BackgroundGeolocation.DesiredAccuracy.Medium,
    showsBackgroundLocationIndicator: false,
    distanceFilter: 1000,
    stationaryRadius: 500,
    disableLocationAuthorizationAlert: true,
    locationAuthorizationAlert: {
      titleWhenNotEnabled: 'background-location not enabled',
      titleWhenOff: 'background-location off',
      instructions: 'grant location permission to my-app',
      cancelButton: 'cancel',
      settingsButton: 'settingsButton',
    },
  },
  // https://transistorsoft.github.io/react-native-background-geolocation/latest/interfaces/ActivityConfig.html
  activity: {
    disableMotionActivityUpdates: true, // not needed
  },
  // https://transistorsoft.github.io/react-native-background-geolocation/latest/interfaces/PersistenceConfig.html
  persistence: {
    maxRecordsToPersist: 25,
    locationTemplate:
      '{ "Latitude":<%= latitude %>, "Longitude":<%= longitude %> }',
  },
  // https://transistorsoft.github.io/react-native-background-geolocation/latest/interfaces/HttpConfig.html
  http: {
    url: 'https://example.com',
    autoSync: true,
    batchSync: false,
    maxBatchSize: 1,
    autoSyncThreshold: 1,
    rootProperty: 'Filters',
  },
  logger: {
    logMaxDays: 1,
    logLevel: BackgroundGeolocation.LogLevel.Debug,
  },
}

v4
{
  startOnBoot: true,
  locationAuthorizationRequest: 'Always',
  useSignificantChangesOnly: true,
  disableMotionActivityUpdates: true,
  desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_MEDIUM, // 👶 ⚙️
  enableHeadless: true,
  stopOnTerminate: false,
  distanceFilter: 1000,
  stationaryRadius: 500,
  preventSuspend: false,
  heartbeatInterval: 2500,
  disableLocationAuthorizationAlert: true,
  locationAuthorizationAlert: {
    titleWhenNotEnabled: 'titleWhenNotEnabled',
    titleWhenOff: 'titleWhenOff',
    instructions: 'instructions here',
    cancelButton: 'cancel',
    settingsButton: 'settings',
  },
  backgroundPermissionRationale: {
    title: 'title',
    message: 'message here',
    positiveAction: 'si si',
    negativeAction: 'cancel',
  },
  locationTimeout: 60,
  logLevel: BackgroundGeolocation.LOG_LEVEL_VERBOSE,
  logMaxDays: 3,
  maxRecordsToPersist: 100,
  showsBackgroundLocationIndicator: false,
  autoSync: true,
  autoSyncThreshold: 1,
  batchSync: true,
  maxBatchSize: 1,
}

Relevant log output

📌 🔒 -[TSTrackingService start:] [start] desiredPolicy=1 status=4 didRequestUpgrade=1 isAuthorizedForPolicy=0
🔵 -[TSConfig onChange:] state.enabled
🟢 -[TSGeofenceManager start]
🟢 -[TSMotionDetector start]
🟢 -[TSMotionDetector startSensorDetection]
🟢 -[TSTrackingService changePace:] isMoving: 0
🔵 -[TSMotionDetector _applySamplingIntervalLocked:] Adaptive sampling -> dt=0.100s (10 Hz)
🟢 -[TSLocationRequestService requestLocation:] [motionchange] maximumAge: 5000
🟢 -[TSDeviceManager startMonitoring]
started ✅
calling getCurrentPosition...
🔵 -[TSTrackingService getCurrentPosition:]
📌 🔒 -[TSLocationAuthorization beginAuthorizationFlow] Have WhenInUse but want Always - requesting Always upgrade (policy=Always, attempted=1)
🟢 -[TSLocationRequestService requestLocation:] [getCurrentPosition] maximumAge: 0
📌 🔒 -[TSLocationAuthorization requestAlwaysUpgrade] Setting state to RequestingAlways and requesting Always authorization
🔵 -[TSHttpService armFlushWatchdog] flush=83438156-E65F-4936-9396-801F10086F90 watchdog_armed timeout=60.000 watchdog=65.000
🟢 -[TSTrackingService startMonitoringBackgroundFetch]
[TSBackgroundFetch start] (null)
[TSBackgroundFetch scheduleBGAppRefresh] com.transistorsoft.fetch
🔵 -[TSTrackingService startMonitoringBackgroundFetch]_block_invoke Configured BackgroundFetch
🟢 -[TSTrackingService startMonitoringSignificantLocationChanges]
'[onLocation]: ', 40.73061, -73.935242
🔵 -[TSTrackingService startMonitoringStationaryRegion:radius:] Radius: 500
🔵 -[TSLocationDAO shrink:db:] Shrank locations to max=25 (deleted 0 rows)
🔴 -[TSTrackingService stopUpdatingLocation]
'[onLocation]: ', 40.73061, -73.935242
'[onLocation]: ', 40.73061, -73.935242
🔵 -[TSHttpService armFlushWatchdog] flush=0BAA2618-0479-4B39-B5D3-862874B84E2C watchdog_armed timeout=60.000 watchdog=65.000
'[onLocation]: ', 40.73061, -73.935242
⚠️ -[TSHttpResponse handleResponse] HTTP ERROR: 405* <!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
🔵 -[TSHttpService doPost:callback:]_block_invoke flush=0BAA2618-0479-4B39-B5D3-862874B84E2C post status=405 retry=0 busy=1
🟢 Posting 'appEntersBackground' event to registered modules
🟢 Posting 'appEntersBackground' event to registered modules
🔵 -[TSAppState onEnterBackground]
🔴 -[TSTrackingService stopUpdatingLocation]
🟢 -[TSTrackingService changePace:] isMoving: 0
🟢 -[TSLocationRequestService requestLocation:] [motionchange] maximumAge: 5000
📌 🔒 -[TSLocationAuthorization onAuthorizationStatusChanged:] Authorization status changed: 2 (state: RequestingAlways)
'[onLocation]: ', 40.73061, -73.935242
'[onProvider] - ', { status: 2,
  enabled: true,
  network: true,
  accuracyAuthorization: 1,
  gps: true }
'[onProviderChange]: ', { status: 2,
  enabled: true,
  network: true,
  accuracyAuthorization: 1,
  gps: true }
⚠️ -[TSLocationRequestService locationManager:didFailWithError:] Error Domain=kCLErrorDomain Code=1 "(null)"
⚠️ -[TSTrackingService changePace:]_block_invoke TODO Failed to fetch motionchange location: Error Domain=kCLErrorDomain Code=1 "(null)"
⚠️ -[TSTrackingService onMotionChangeError:] Failed to receive motionchange location with error:  Error Domain=kCLErrorDomain Code=1 "(null)"
🟢 -[TSTrackingService startMonitoringSignificantLocationChanges]
⚠️ -[TSLocationRequestService locationManager:didFailWithError:] Error Domain=kCLErrorDomain Code=1 "(null)"
'[BackgroundGeolocation] init error:', { [Error: The operation couldn’t be completed. (kCLErrorDomain error 1.)]
  code: 'get_current_position_error',
  nativeStackIOS: 
   [ '0   React                               0x000000010aa09600 RCTJSErrorFromCodeMessageAndNSError + 100',
     '1   React                               0x000000010b42308c ___ZZN8facebook5react15ObjCTurboModule13createPromiseERNS_3jsi7RuntimeERKNSt3__112basic_stringIcNS5_11char_traitsIcEENS5_9allocatorIcEEEEU13block_pointerFvU13block_pointerFvP11objc_objectEU13block_pointerFvP8NSStringSJ_P7NSErrorEEENK3$_0clES4_RKNS2_5ValueEPSS_m_block_invoke.114 + 652',
     '2   myapp.debug.dylib                   0x00000001065da14c __61-[RNBackgroundGeolocation getCurrentPosition:resolve:reject:]_block_invoke.111 + 116',
     '3   myapp.debug.dylib                   0x0000000106606f44 __40-[TSTrackingService getCurrentPosition:]_block_invoke.170 + 92',
     '4   myapp.debug.dylib                   0x0000000106649df8 __67-[TSLocationRequestService completeRequest:success:location:error:]_block_invoke + 136',
     '5   Foundation                          0x00000001810729cc __NSINDEXSET_IS_CALLING_OUT_TO_A_BOOL_BLOCK__ + 16',
     '6   Foundation                          0x00000001810cea3c -[NSBlockOperation main] + 84',
     '7   Foundation                          0x00000001810d15f8 __NSOPERATION_IS_INVOKING_MAIN__ + 12',
     '8   Foundation                          0x00000001810cdd94 -[NSOperation start] + 612',
     '9   Foundation                          0x00000001810d1dfc __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 12',
     '10  Foundation                          0x00000001810d1a2c __NSOQSchedule_f + 160',
     '11  libdispatch.dylib                   0x0000000105abf8ac _dispatch_block_async_invoke2 + 104',
     '12  libdispatch.dylib                   0x0000000105ac9374 _dispatch_client_callout + 12',
     '13  libdispatch.dylib                   0x0000000105abeff0 _dispatch_main_queue_drain + 1208',
     '14  libdispatch.dylib                   0x0000000105abeb28 _dispatch_main_queue_callback_4CF + 40',
     '15  CoreFoundation                      0x00000001804204c0 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12',
     '16  CoreFoundation                      0x000000018041f698 __CFRunLoopRun + 1884',
     '17  CoreFoundation                      0x000000018041a330 _CFRunLoopRunSpecificWithOptions + 496',
     '18  GraphicsServices                    0x00000001932cb9c0 GSEventRunModal + 116',
     '19  UIKitCore                           0x000000018647a474 -[UIApplication _run] + 776',
     '20  UIKitCore                           0x0000000186b747fc UIApplicationMain + 120',
     '21  UIKitCore                           0x0000000185620760 block_destroy_helper.15 + 4692',
     '22  myapp.debug.dylib                   0x00000001063a004c $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 128',
     '23  myapp.debug.dylib                   0x000000010639ffbc $s5myapp11AppDelegateC5$mainyyFZ + 44',
     '24  myapp.debug.dylib                   0x00000001063a0af0 __debug_main_executable_dylib_entry_point + 28',
     '25  dyld                                0x0000000104f230b4 start_sim + 20',
     '26  ???                                 0x0000000104ffbda4 0x0 + 4378836388' ],
  domain: 'kCLErrorDomain',
  userInfo: {} }
'[onLocation]: NO COORDS ', { error: 1 }
'[onLocation]: NO COORDS ', { error: 1 }
🟢 Posting 'appEntersForeground' event to registered modules
🟢 Posting 'appEntersForeground' event to registered modules
🔵 -[TSAppState onEnterForeground]
🔵 -[TSTrackingService onResume] enabled? 1
🔵 -[TSLocationDAO purge:] 1
🔵 -[TSHttpService armFlushWatchdog] flush=213D4B73-A298-46F4-A00D-95C0B7F3634E watchdog_armed timeout=60.000 watchdog=65.000
⚠️ -[TSTrackingService locationManager:didFailWithError:] Error Domain=kCLErrorDomain Code=1 "(null)"
'[onLocation]: NO COORDS ', { error: 1 }
⚠️ -[TSHttpResponse handleResponse] HTTP ERROR: 405* <!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
🔵 -[TSHttpService doPost:callback:]_block_invoke flush=213D4B73-A298-46F4-A00D-95C0B7F3634E post status=405 retry=0 busy=1
🟢 Posting 'appBecomesActive' event to registered modules
🟢 Posting 'appBecomesActive' event to registered modules
📌 🔒 -[TSLocationAuthorization applicationDidBecomeActive] Application became active - refreshing authorization state
📌 🔒 -[TSLocationAuthorization applicationDidBecomeActive] Not authorized - starting authorization flow
📌 🔒 -[TSLocationAuthorization applicationDidBecomeActive]_block_invoke Authorization completed from applicationDidBecomeActive: status=2, error=Error Domain=TSLocationAuthorizationErrorDomain Code=1001 "Location services disabled" UserInfo={NSLocalizedDescription=Location services disabled}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions