fix(track-location): try 7 (+ up rnbl to v5)
This commit is contained in:
parent
b61aff7078
commit
f4f7708e71
12 changed files with 293 additions and 188 deletions
|
|
@ -16,5 +16,5 @@ ASC_API_KEY_PATH=
|
||||||
PROVIDER_ID=
|
PROVIDER_ID=
|
||||||
|
|
||||||
# Background Geolocation License Keys
|
# Background Geolocation License Keys
|
||||||
BACKGROUND_GEOLOCATION_LICENSE=your_license_key_here
|
BACKGROUND_GEOLOCATION_LICENSE_ANDROID=your_license_key_here
|
||||||
BACKGROUND_GEOLOCATION_HMS_LICENSE=your_hms_license_key_here
|
BACKGROUND_GEOLOCATION_LICENSE_IOS=your_license_key_here
|
||||||
|
|
@ -37,8 +37,7 @@
|
||||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:networkSecurityConfig="@xml/network_security_config" android:fullBackupContent="@xml/secure_store_backup_rules" android:dataExtractionRules="@xml/secure_store_data_extraction_rules">
|
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:networkSecurityConfig="@xml/network_security_config" android:fullBackupContent="@xml/secure_store_backup_rules" android:dataExtractionRules="@xml/secure_store_data_extraction_rules">
|
||||||
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/notification_icon_color" tools:replace="android:resource"/>
|
<meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/notification_icon_color" tools:replace="android:resource"/>
|
||||||
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon"/>
|
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/notification_icon"/>
|
||||||
<meta-data android:name="com.transistorsoft.locationmanager.hms.license" android:value="ba479a3c61fbe471c826a39d1ee8b1a088df6d2249fad51f6ab5f24346f6bf87"/>
|
<meta-data android:name="com.transistorsoft.locationmanager.license" android:value="eyJhbGciOiJFZERTQSIsImtpZCI6ImVkMjU1MTktbWFpbi12MSJ9.eyJvcyI6ImFuZHJvaWQiLCJhcHBfaWQiOiJjb20uYWxlcnRlc2Vjb3VycyIsIm9yZGVyX251bWJlciI6ODY0MCwicmVuZXdhbF91cmwiOiJodHRwczovL3Nob3AudHJhbnNpc3RvcnNvZnQuY29tL2NhcnQvMTY1MDc4NjE1MDU6MT9ub3RlPTYxOTMiLCJjdXN0b21lcl9pZCI6NTc0MiwicHJvZHVjdCI6InJlYWN0LW5hdGl2ZS1iYWNrZ3JvdW5kLWdlb2xvY2F0aW9uIiwia2V5X3ZlcnNpb24iOjEsImFsbG93ZWRfc3VmZml4ZXMiOlsiLmRldiIsIi5kZXZlbG9wbWVudCIsIi5zdGFnaW5nIiwiLnN0YWdlIiwiLnFhIiwiLnVhdCIsIi50ZXN0IiwiLmRlYnVnIl0sIm1heF9idWlsZF9zdGFtcCI6MjAyNzAyMjIsImdyYWNlX2J1aWxkcyI6MCwiZW50aXRsZW1lbnRzIjpbImNvcmUiXSwiaWF0IjoxNzY5MTI2Mjg5fQ.sCJRdXJ78r2B0BLfht-AnYXSoF5pcTxAfEkCcX6BN7FiYc8GT9RUMlqDdwacD6UlI0v6WLhQck6lPkRgCq4MDQ"/>
|
||||||
<meta-data android:name="com.transistorsoft.locationmanager.license" android:value="90f34e070bebc8e433a9b604e1728dfa17a62ab484602e3cb7ef7ece784a23eb"/>
|
|
||||||
<meta-data android:name="expo.modules.notifications.default_notification_color" android:resource="@color/notification_icon_color"/>
|
<meta-data android:name="expo.modules.notifications.default_notification_color" android:resource="@color/notification_icon_color"/>
|
||||||
<meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/notification_icon"/>
|
<meta-data android:name="expo.modules.notifications.default_notification_icon" android:resource="@drawable/notification_icon"/>
|
||||||
<meta-data android:name="expo.modules.updates.CODE_SIGNING_CERTIFICATE" android:value="-----BEGIN CERTIFICATE-----
MIICzTCCAbWgAwIBAgIJR0KfFDoMJrYZMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV
BAMTBHRlc3QwIBcNMjQwODE4MTU0OTExWhgPMjEyNDA4MTgxNTQ5MTFaMA8xDTAL
BgNVBAMTBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCk46qR
a0Do2fpBDtif18a/WQNWHm/xseHsh97bZdt8ooV4PQooK6VZUbADUhhJXqqomapa
yFMJX7sZzfBUF7/xMrWDrgS0R4FLbXijAolhpXoqMkBCx3toKUCbU4ljA+Lz/BX1
AEqVWqAweNzNDi4bvd1PG1/sQuuEtoZuSVfTPRAjF8vVkWyn8nfkorTtMYaw2QFu
ugs1wp7YieD4C8CIK5gMX7f8bxx3l7BR50bf+9MHJFI+eTjmoFoJFEVWbCcrOrky
FLM0+NrMI2fZYunrN6jcKc/NKEaDKb1VDO9yrLcFQOtXJJIXz94/lS6kHDjzEgUV
zx3uaDbAdSQsyZxxAgMBAAGjKjAoMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8E
DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEASIjMvS3N9NEPeakUmYXg
MEyjaX+N/62Pbcp4taU4G9vDB/fyDqMMef8+CWBpo/noXqzt4K6k1id7UwdZhRks
xdBTSf1x5yzDB24mbqNAvPa2q8G6KIoNZuvLUDz35366FxR+vTHQmp2d4Yz92kIL
EEmFr8eMHf60tfHG+em97p+evmXDyBjF3CwOvtuzog1wCF/AsJ1d0gbPPMKdAHKC
LZHsiXJ5i/oFuYzWkDDJkO9bb6HaQplt/46iC0CyM6SsT6H8kkDVQbfQCH1JAXsL
Knk10FbAMKJ7GWbAdsdcbNZlDMrzPprw8N/fpGc7RHdHBwKcFm44mNtrMrzEd4eX
pQ==
-----END CERTIFICATE-----
"/>
|
<meta-data android:name="expo.modules.updates.CODE_SIGNING_CERTIFICATE" android:value="-----BEGIN CERTIFICATE-----
MIICzTCCAbWgAwIBAgIJR0KfFDoMJrYZMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV
BAMTBHRlc3QwIBcNMjQwODE4MTU0OTExWhgPMjEyNDA4MTgxNTQ5MTFaMA8xDTAL
BgNVBAMTBHRlc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCk46qR
a0Do2fpBDtif18a/WQNWHm/xseHsh97bZdt8ooV4PQooK6VZUbADUhhJXqqomapa
yFMJX7sZzfBUF7/xMrWDrgS0R4FLbXijAolhpXoqMkBCx3toKUCbU4ljA+Lz/BX1
AEqVWqAweNzNDi4bvd1PG1/sQuuEtoZuSVfTPRAjF8vVkWyn8nfkorTtMYaw2QFu
ugs1wp7YieD4C8CIK5gMX7f8bxx3l7BR50bf+9MHJFI+eTjmoFoJFEVWbCcrOrky
FLM0+NrMI2fZYunrN6jcKc/NKEaDKb1VDO9yrLcFQOtXJJIXz94/lS6kHDjzEgUV
zx3uaDbAdSQsyZxxAgMBAAGjKjAoMA4GA1UdDwEB/wQEAwIHgDAWBgNVHSUBAf8E
DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEASIjMvS3N9NEPeakUmYXg
MEyjaX+N/62Pbcp4taU4G9vDB/fyDqMMef8+CWBpo/noXqzt4K6k1id7UwdZhRks
xdBTSf1x5yzDB24mbqNAvPa2q8G6KIoNZuvLUDz35366FxR+vTHQmp2d4Yz92kIL
EEmFr8eMHf60tfHG+em97p+evmXDyBjF3CwOvtuzog1wCF/AsJ1d0gbPPMKdAHKC
LZHsiXJ5i/oFuYzWkDDJkO9bb6HaQplt/46iC0CyM6SsT6H8kkDVQbfQCH1JAXsL
Knk10FbAMKJ7GWbAdsdcbNZlDMrzPprw8N/fpGc7RHdHBwKcFm44mNtrMrzEd4eX
pQ==
-----END CERTIFICATE-----
"/>
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,7 @@ apply plugin: "com.facebook.react.rootproject"
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
// @generated begin react-native-background-fetch-maven - expo prebuild (DO NOT MODIFY) sync-b86324ce2eb77b03cc8b69ba206ef8275cd006ff
|
maven {
|
||||||
maven { url "${project(":react-native-background-fetch").projectDir}/libs" }
|
|
||||||
// @generated begin react-native-background-geolocation-maven - expo prebuild (DO NOT MODIFY) sync-4b2bae87fd8579c445d8885f6bdc8542d9d0bbca
|
|
||||||
maven { url "${project(":react-native-background-geolocation").projectDir}/libs" }
|
|
||||||
maven { url 'https://developer.huawei.com/repo/' }
|
|
||||||
// @generated end react-native-background-geolocation-maven
|
|
||||||
// @generated end react-native-background-fetch-maven
|
|
||||||
maven {
|
|
||||||
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
|
||||||
url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
|
url(new File(['node', '--print', "require.resolve('react-native/package.json')"].execute(null, rootDir).text.trim(), '../android'))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -140,15 +140,9 @@ let config = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
UIBackgroundModes: ["location", "fetch", "processing"],
|
UIBackgroundModes: ["location", "fetch", "processing"],
|
||||||
|
TSLocationManagerLicense: process.env.BACKGROUND_GEOLOCATION_LICENSE_IOS,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
[
|
|
||||||
"react-native-background-geolocation",
|
|
||||||
{
|
|
||||||
license: process.env.BACKGROUND_GEOLOCATION_LICENSE,
|
|
||||||
hmsLicense: process.env.BACKGROUND_GEOLOCATION_HMS_LICENSE,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
"expo-gradle-ext-vars",
|
"expo-gradle-ext-vars",
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ The app uses environment variables for configuration and sensitive information.
|
||||||
Copy `.env.default` to `.env.local` (which is git-ignored) and fill in the required values:
|
Copy `.env.default` to `.env.local` (which is git-ignored) and fill in the required values:
|
||||||
|
|
||||||
- `BACKGROUND_GEOLOCATION_LICENSE`: License key for react-native-background-geolocation
|
- `BACKGROUND_GEOLOCATION_LICENSE`: License key for react-native-background-geolocation
|
||||||
- `BACKGROUND_GEOLOCATION_HMS_LICENSE`: HMS license key for react-native-background-geolocation
|
|
||||||
|
|
||||||
### Production Environment
|
### Production Environment
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,14 +15,14 @@ Applies to the BackgroundGeolocation integration:
|
||||||
## Current implementation notes
|
## Current implementation notes
|
||||||
|
|
||||||
- Movement-driven recording only:
|
- Movement-driven recording only:
|
||||||
- IDLE uses `distanceFilter: 200` (aim: no updates while not moving).
|
- IDLE uses `geolocation.distanceFilter: 200` (aim: no updates while not moving).
|
||||||
- ACTIVE uses `distanceFilter: 25`.
|
- ACTIVE uses `geolocation.distanceFilter: 25`.
|
||||||
- JS may request a persisted fix when entering ACTIVE (see [`applyProfile()`](src/location/trackLocation.js:351)).
|
- JS may request a persisted fix when entering ACTIVE (see [`applyProfile()`](src/location/trackLocation.js:351)).
|
||||||
- Upload strategy is intentionally simple:
|
- Upload strategy is intentionally simple:
|
||||||
- Keep only the latest persisted geopoint: `maxRecordsToPersist: 1`.
|
- Keep only the latest persisted geopoint: `persistence.maxRecordsToPersist: 1`.
|
||||||
- No batching / thresholds: `batchSync: false`, `autoSyncThreshold: 0`.
|
- No batching / thresholds: `batchSync: false`, `autoSyncThreshold: 0`.
|
||||||
- When authenticated, each persisted location should upload immediately via native HTTP (works while JS is suspended).
|
- When authenticated, each persisted location should upload immediately via native HTTP (works while JS is suspended).
|
||||||
- Pre-auth: tracking may persist locally but `url` is empty so nothing is uploaded until auth is ready.
|
- Pre-auth: tracking may persist locally but `http.url` is empty so nothing is uploaded until auth is ready.
|
||||||
|
|
||||||
## Basic preconditions
|
## Basic preconditions
|
||||||
|
|
||||||
|
|
@ -69,18 +69,40 @@ Applies to the BackgroundGeolocation integration:
|
||||||
### Android
|
### Android
|
||||||
|
|
||||||
1. Ensure tracking enabled and authenticated.
|
1. Ensure tracking enabled and authenticated.
|
||||||
2. Force-stop the app task.
|
2. Swipe the app away from recents / kill the task.
|
||||||
3. Move ~250m in IDLE.
|
3. Move ~250m in IDLE.
|
||||||
- Expect: native service still records + uploads.
|
- Expect: native service still records + uploads.
|
||||||
4. Move ~30m in ACTIVE.
|
4. Move ~30m in ACTIVE.
|
||||||
- Expect: native service still records + uploads.
|
- Expect: native service still records + uploads.
|
||||||
|
|
||||||
|
> Note: This does **not** include Android Settings → **Force stop**.
|
||||||
|
> Force-stop prevents background services and receivers from running; no SDK can reliably track after that.
|
||||||
|
|
||||||
### iOS
|
### iOS
|
||||||
|
|
||||||
1. Swipe-kill the app.
|
1. Swipe-kill the app.
|
||||||
2. Move significantly (expect iOS to relaunch app on stationary-geofence exit).
|
2. Move significantly (expect iOS to relaunch app on stationary-geofence exit).
|
||||||
- Expect: tracking resumes and uploads after movement.
|
- Expect: tracking resumes and uploads after movement.
|
||||||
|
|
||||||
|
## Test matrix (quick)
|
||||||
|
|
||||||
|
| Platform | App state | Profile | Move | Expected signals |
|
||||||
|
|---|---|---|---:|---|
|
||||||
|
| Android | foreground | IDLE | ~250m | [`onLocation`](src/location/trackLocation.js:693) (sample=false), then [`onHttp`](src/location/trackLocation.js:733) |
|
||||||
|
| Android | background | IDLE | ~250m | same as above |
|
||||||
|
| Android | swipe-away | IDLE | ~250m | native persists + uploads; verify server + `onHttp` when app relaunches |
|
||||||
|
| Android | foreground | ACTIVE | ~30m | location + upload continues |
|
||||||
|
| iOS | background | IDLE | ~250m | movement-driven update; no periodic uploads while stationary |
|
||||||
|
| iOS | swipe-killed | IDLE | significant | OS relaunch on movement; upload after relaunch |
|
||||||
|
|
||||||
|
## What to look for in logs
|
||||||
|
|
||||||
|
- App lifecycle tagging: [`updateTrackingContextExtras()`](src/location/trackLocation.js:63) should update `tracking_ctx.app_state` on AppState changes.
|
||||||
|
- No time-based uploads: heartbeat is disabled (`heartbeatInterval: 0`), so no `Heartbeat` logs from [`onHeartbeat`](src/location/trackLocation.js:762).
|
||||||
|
- Movement-only uploads:
|
||||||
|
- IDLE distance threshold: `distanceFilter: 200` in [`TRACKING_PROFILES`](src/location/backgroundGeolocationConfig.js:148).
|
||||||
|
- ACTIVE distance threshold: `distanceFilter: 25` in [`TRACKING_PROFILES`](src/location/backgroundGeolocationConfig.js:148).
|
||||||
|
|
||||||
## Debugging tips
|
## Debugging tips
|
||||||
|
|
||||||
- Observe logs in app:
|
- Observe logs in app:
|
||||||
|
|
|
||||||
|
|
@ -146,6 +146,8 @@
|
||||||
<string>[Alerte-Secours] Cette application utilise les notifications pour pouvoir vous prévenir lorsque quelqu'un a besoin d'aide à proximité</string>
|
<string>[Alerte-Secours] Cette application utilise les notifications pour pouvoir vous prévenir lorsque quelqu'un a besoin d'aide à proximité</string>
|
||||||
<key>NSUserNotificationUsageDescription</key>
|
<key>NSUserNotificationUsageDescription</key>
|
||||||
<string>Alerte-Secours utilise les notifications pour vous informer immédiatement lorsqu'une personne à proximité nécessite une assistance urgente. Ces alertes sont essentielles pour une réponse rapide aux situations d'urgence.</string>
|
<string>Alerte-Secours utilise les notifications pour vous informer immédiatement lorsqu'une personne à proximité nécessite une assistance urgente. Ces alertes sont essentielles pour une réponse rapide aux situations d'urgence.</string>
|
||||||
|
<key>TSLocationManagerLicense</key>
|
||||||
|
<string>eyJhbGciOiJFZERTQSIsImtpZCI6ImVkMjU1MTktbWFpbi12MSJ9.eyJvcyI6ImlvcyIsImFwcF9pZCI6ImNvbS5hbGVydGVzZWNvdXJzLmFsZXJ0ZXNlY291cnMiLCJvcmRlcl9udW1iZXIiOjg2NDAsInJlbmV3YWxfdXJsIjoiaHR0cHM6Ly9zaG9wLnRyYW5zaXN0b3Jzb2Z0LmNvbS9jYXJ0LzE2NTA3ODYxNTA1OjE_bm90ZT02MTkzIiwiY3VzdG9tZXJfaWQiOjU3NDIsInByb2R1Y3QiOiJyZWFjdC1uYXRpdmUtYmFja2dyb3VuZC1nZW9sb2NhdGlvbiIsImtleV92ZXJzaW9uIjoxLCJhbGxvd2VkX3N1ZmZpeGVzIjpbIi5kZXYiLCIuZGV2ZWxvcG1lbnQiLCIuc3RhZ2luZyIsIi5zdGFnZSIsIi5xYSIsIi51YXQiLCIudGVzdCIsIi5kZWJ1ZyJdLCJtYXhfYnVpbGRfc3RhbXAiOjIwMjcwMjIyLCJncmFjZV9idWlsZHMiOjAsImVudGl0bGVtZW50cyI6WyJjb3JlIl0sImlhdCI6MTc2OTEyNjI4OX0.bOJmTwxkRlRVAMHuNeXUVlSFTQyai3wal2TEz6jlOvEHFadbP6WG0E_KUMatinSRgKEIxs0L_SmSn6G5eWAYDQ</string>
|
||||||
<key>UIBackgroundModes</key>
|
<key>UIBackgroundModes</key>
|
||||||
<array>
|
<array>
|
||||||
<string>fetch</string>
|
<string>fetch</string>
|
||||||
|
|
|
||||||
|
|
@ -178,7 +178,7 @@
|
||||||
"react-native-animatable": "^1.3.3",
|
"react-native-animatable": "^1.3.3",
|
||||||
"react-native-app-link": "^1.0.1",
|
"react-native-app-link": "^1.0.1",
|
||||||
"react-native-background-fetch": "^4.2.8",
|
"react-native-background-fetch": "^4.2.8",
|
||||||
"react-native-background-geolocation": "^4.19.0",
|
"react-native-background-geolocation": "5.0.1",
|
||||||
"react-native-battery-optimization-check": "^1.0.8",
|
"react-native-battery-optimization-check": "^1.0.8",
|
||||||
"react-native-contact-pick": "^0.1.2",
|
"react-native-contact-pick": "^0.1.2",
|
||||||
"react-native-country-picker-modal": "^2.0.0",
|
"react-native-country-picker-modal": "^2.0.0",
|
||||||
|
|
@ -282,4 +282,4 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@4.5.3"
|
"packageManager": "yarn@4.5.3"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,142 +19,166 @@ import env from "~/env";
|
||||||
// - ACTIVE (open alert): first location should reach server within seconds, then continuous distance-based updates.
|
// - ACTIVE (open alert): first location should reach server within seconds, then continuous distance-based updates.
|
||||||
//
|
//
|
||||||
// Notes:
|
// Notes:
|
||||||
// - We avoid `reset: true` in production because it can unintentionally wipe persisted / configured state.
|
// - We keep config deterministic across launches to avoid stale persisted settings creating
|
||||||
// In dev, `reset: true` is useful to avoid config drift while iterating.
|
// unexpected periodic wakeups/uploads.
|
||||||
// - `maxRecordsToPersist` must be > 1 to support offline catch-up.
|
// - `maxRecordsToPersist: 1` matches product requirement (only latest geopoint).
|
||||||
export const BASE_GEOLOCATION_CONFIG = {
|
export const BASE_GEOLOCATION_CONFIG = {
|
||||||
// Android Headless Mode
|
|
||||||
// We do not require JS execution while terminated. Native tracking + native HTTP upload
|
|
||||||
// are sufficient for our needs (stopOnTerminate:false).
|
|
||||||
enableHeadless: false,
|
|
||||||
|
|
||||||
// Default to low-power (idle) profile; will be overridden when needed.
|
|
||||||
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_LOW,
|
|
||||||
|
|
||||||
// Default to the IDLE profile behaviour: we still want distance-based updates
|
|
||||||
// even with no open alert (see TRACKING_PROFILES.idle).
|
|
||||||
distanceFilter: 200,
|
|
||||||
|
|
||||||
// Activity-recognition stop-detection.
|
|
||||||
// NOTE: Transistorsoft defaults `stopTimeout` to 5 minutes (see
|
|
||||||
// [`node_modules/react-native-background-geolocation/src/declarations/interfaces/Config.d.ts:79`](node_modules/react-native-background-geolocation/src/declarations/interfaces/Config.d.ts:79)).
|
|
||||||
stopTimeout: 5,
|
|
||||||
|
|
||||||
// debug: true,
|
|
||||||
// Logging can become large and also adds overhead; keep verbose logs to dev/staging.
|
|
||||||
logLevel:
|
|
||||||
__DEV__ || env.IS_STAGING
|
|
||||||
? BackgroundGeolocation.LOG_LEVEL_VERBOSE
|
|
||||||
: BackgroundGeolocation.LOG_LEVEL_ERROR,
|
|
||||||
|
|
||||||
// Permission request strategy
|
|
||||||
locationAuthorizationRequest: "Always",
|
|
||||||
|
|
||||||
// Lifecycle
|
|
||||||
stopOnTerminate: false,
|
|
||||||
startOnBoot: true,
|
|
||||||
|
|
||||||
// Background scheduling
|
|
||||||
// Disable heartbeats by default to avoid periodic background wakeups while stationary.
|
|
||||||
// ACTIVE profile will explicitly enable a fast heartbeat when needed.
|
|
||||||
heartbeatInterval: 0,
|
|
||||||
|
|
||||||
// Android foreground service
|
|
||||||
foregroundService: true,
|
|
||||||
notification: {
|
|
||||||
title: "Alerte Secours",
|
|
||||||
text: "Suivi de localisation actif",
|
|
||||||
channelName: "Location tracking",
|
|
||||||
priority: BackgroundGeolocation.NOTIFICATION_PRIORITY_HIGH,
|
|
||||||
},
|
|
||||||
|
|
||||||
// Android 10+ rationale dialog
|
|
||||||
backgroundPermissionRationale: {
|
|
||||||
title:
|
|
||||||
"Autoriser Alerte-Secours à accéder à la localisation en arrière-plan",
|
|
||||||
message:
|
|
||||||
"Alerte-Secours nécessite la localisation en arrière-plan pour vous alerter en temps réel lorsqu'une personne à proximité a besoin d'aide urgente. Cette fonction est essentielle pour permettre une intervention rapide et efficace en cas d'urgence.",
|
|
||||||
positiveAction: "Autoriser",
|
|
||||||
negativeAction: "Désactiver",
|
|
||||||
},
|
|
||||||
|
|
||||||
// HTTP configuration
|
|
||||||
// IMPORTANT: Default to uploads disabled until we have an auth token.
|
|
||||||
// Authenticated mode will set `url` + `Authorization` header and enable `autoSync`.
|
|
||||||
url: "",
|
|
||||||
method: "POST",
|
|
||||||
httpRootProperty: "location",
|
|
||||||
// Keep uploads simple: 1 location record -> 1 HTTP request.
|
|
||||||
// (We intentionally keep only the latest record; batching provides no benefit.)
|
|
||||||
autoSync: false,
|
|
||||||
// Ensure no persisted config can keep batching/threshold behavior.
|
|
||||||
batchSync: false,
|
|
||||||
autoSyncThreshold: 0,
|
|
||||||
|
|
||||||
// Persistence
|
|
||||||
// Product requirement: keep only the latest geopoint. This reduces on-device storage
|
|
||||||
// and avoids building up a queue.
|
|
||||||
// NOTE: This means we intentionally do not support offline catch-up of multiple points.
|
|
||||||
maxRecordsToPersist: 1,
|
|
||||||
maxDaysToPersist: 1,
|
|
||||||
|
|
||||||
// IMPORTANT: Keep config deterministic across upgrades.
|
|
||||||
// `reset: false` causes the SDK to ignore changes in `ready(config)` after first install.
|
|
||||||
// This can leave old values (eg heartbeatInterval) lingering and creating periodic uploads.
|
|
||||||
reset: true,
|
reset: true,
|
||||||
|
|
||||||
// Behavior tweaks
|
// Logger config
|
||||||
disableProviderChangeRecord: true,
|
logger: {
|
||||||
|
// debug: true,
|
||||||
|
// Logging can become large and also adds overhead; keep verbose logs to dev/staging.
|
||||||
|
logLevel:
|
||||||
|
__DEV__ || env.IS_STAGING
|
||||||
|
? BackgroundGeolocation.LogLevel.Verbose
|
||||||
|
: BackgroundGeolocation.LogLevel.Error,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Geolocation config
|
||||||
|
geolocation: {
|
||||||
|
// Default profile is IDLE.
|
||||||
|
//
|
||||||
|
// Important: `DesiredAccuracy.Low` (wifi/cell) can yield very large errors (km-level).
|
||||||
|
// Those poor fixes can create false motion/geofence transitions on some Android devices,
|
||||||
|
// resulting in periodic uploads while the user is stationary.
|
||||||
|
//
|
||||||
|
// We default to a GPS-capable accuracy but rely on motion + distance thresholds to
|
||||||
|
// protect battery.
|
||||||
|
desiredAccuracy: BackgroundGeolocation.DesiredAccuracy.High,
|
||||||
|
|
||||||
|
// Default to the IDLE profile behaviour: we still want distance-based updates
|
||||||
|
// even with no open alert (see TRACKING_PROFILES.idle).
|
||||||
|
distanceFilter: 200,
|
||||||
|
|
||||||
|
// Stop-detection.
|
||||||
|
// NOTE: historically we set this at top-level. In v5 the knob is under `geolocation`.
|
||||||
|
stopTimeout: 5,
|
||||||
|
|
||||||
|
// Permission request strategy
|
||||||
|
locationAuthorizationRequest: "Always",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Application / lifecycle config
|
||||||
|
app: {
|
||||||
|
// Android Headless Mode
|
||||||
|
// We do not require JS execution while terminated. Native tracking + native HTTP upload
|
||||||
|
// are sufficient for our needs (stopOnTerminate:false).
|
||||||
|
enableHeadless: false,
|
||||||
|
|
||||||
|
stopOnTerminate: false,
|
||||||
|
startOnBoot: true,
|
||||||
|
|
||||||
|
// Background scheduling
|
||||||
|
// Disable heartbeats to avoid periodic background wakeups while stationary.
|
||||||
|
heartbeatInterval: 0,
|
||||||
|
|
||||||
|
// Android foreground service notification
|
||||||
|
notification: {
|
||||||
|
title: "Alerte Secours",
|
||||||
|
text: "Suivi de localisation actif",
|
||||||
|
channelName: "Location tracking",
|
||||||
|
priority: BackgroundGeolocation.NotificationPriority.High,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Android 10+ rationale dialog
|
||||||
|
backgroundPermissionRationale: {
|
||||||
|
title:
|
||||||
|
"Autoriser Alerte-Secours à accéder à la localisation en arrière-plan",
|
||||||
|
message:
|
||||||
|
"Alerte-Secours nécessite la localisation en arrière-plan pour vous alerter en temps réel lorsqu'une personne à proximité a besoin d'aide urgente. Cette fonction est essentielle pour permettre une intervention rapide et efficace en cas d'urgence.",
|
||||||
|
positiveAction: "Autoriser",
|
||||||
|
negativeAction: "Désactiver",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// HTTP config
|
||||||
|
// IMPORTANT: Default to uploads disabled until we have an auth token.
|
||||||
|
// Authenticated mode will set `http.url` + `Authorization` header and enable `autoSync`.
|
||||||
|
http: {
|
||||||
|
url: "",
|
||||||
|
method: BackgroundGeolocation.HttpMethod.POST,
|
||||||
|
rootProperty: "location",
|
||||||
|
// Keep uploads simple: 1 location record -> 1 HTTP request.
|
||||||
|
// (We intentionally keep only the latest record; batching provides no benefit.)
|
||||||
|
autoSync: false,
|
||||||
|
// Ensure no persisted config can keep batching/threshold behavior.
|
||||||
|
batchSync: false,
|
||||||
|
autoSyncThreshold: 0,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Persistence config
|
||||||
|
persistence: {
|
||||||
|
// Product requirement: keep only the latest geopoint.
|
||||||
|
maxRecordsToPersist: 1,
|
||||||
|
maxDaysToPersist: 1,
|
||||||
|
|
||||||
|
// Behavior tweaks
|
||||||
|
disableProviderChangeRecord: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Options we want to be stable across launches even when the plugin loads a persisted config.
|
// Options we want to be stable across launches even when the plugin loads a persisted config.
|
||||||
// NOTE: We intentionally do *not* include HTTP auth headers here.
|
// NOTE: We intentionally do *not* include HTTP auth headers here.
|
||||||
export const BASE_GEOLOCATION_INVARIANTS = {
|
export const BASE_GEOLOCATION_INVARIANTS = {
|
||||||
enableHeadless: false,
|
app: {
|
||||||
stopOnTerminate: false,
|
enableHeadless: false,
|
||||||
startOnBoot: true,
|
stopOnTerminate: false,
|
||||||
foregroundService: true,
|
startOnBoot: true,
|
||||||
disableProviderChangeRecord: true,
|
// Never allow background heartbeats by default (prevents time-based wakeups/uploads).
|
||||||
// Never allow background heartbeats by default (prevents time-based wakeups/uploads).
|
heartbeatInterval: 0,
|
||||||
heartbeatInterval: 0,
|
},
|
||||||
// Filter extreme GPS teleports that can create false uploads while stationary.
|
http: {
|
||||||
// Units: meters/second. 100 m/s ~= 360 km/h.
|
method: BackgroundGeolocation.HttpMethod.POST,
|
||||||
speedJumpFilter: 100,
|
rootProperty: "location",
|
||||||
method: "POST",
|
autoSync: false,
|
||||||
httpRootProperty: "location",
|
batchSync: false,
|
||||||
autoSync: false,
|
autoSyncThreshold: 0,
|
||||||
batchSync: false,
|
},
|
||||||
autoSyncThreshold: 0,
|
persistence: {
|
||||||
maxRecordsToPersist: 1,
|
maxRecordsToPersist: 1,
|
||||||
maxDaysToPersist: 1,
|
maxDaysToPersist: 1,
|
||||||
|
disableProviderChangeRecord: true,
|
||||||
|
},
|
||||||
|
// NOTE: `speedJumpFilter` was a legacy Config knob; it is not part of v5 shared types.
|
||||||
|
// If we still want jump filtering, we'll need to implement a server-side filter or
|
||||||
|
// re-introduce a supported SDK filter (eg `geolocation.filter`) when available.
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TRACKING_PROFILES = {
|
export const TRACKING_PROFILES = {
|
||||||
idle: {
|
idle: {
|
||||||
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_LOW,
|
geolocation: {
|
||||||
// Defensive: keep the distanceFilter conservative to avoid battery drain.
|
// Same rationale as BASE: prefer GPS-capable accuracy to avoid km-level coarse fixes
|
||||||
distanceFilter: 200,
|
// that can trigger false motion/geofence transitions on Android.
|
||||||
|
desiredAccuracy: BackgroundGeolocation.DesiredAccuracy.High,
|
||||||
// Never use heartbeat-driven updates; only movement-driven.
|
// Defensive: keep the distanceFilter conservative to avoid battery drain.
|
||||||
heartbeatInterval: 0,
|
distanceFilter: 200,
|
||||||
|
},
|
||||||
// Keep the plugin's speed-based distanceFilter scaling enabled (default).
|
app: {
|
||||||
// This yields fewer updates as speed increases (highway speeds) and helps battery.
|
// Never use heartbeat-driven updates; only movement-driven.
|
||||||
// We intentionally do NOT set `disableElasticity: true`.
|
heartbeatInterval: 0,
|
||||||
|
},
|
||||||
// Android-only: reduce false-positive motion triggers due to screen-on/unlock.
|
activity: {
|
||||||
// (This is ignored on iOS.)
|
// Android-only: reduce false-positive motion triggers due to screen-on/unlock.
|
||||||
motionTriggerDelay: 30000,
|
// We keep Motion API enabled (battery-optimized) but add a large delay so brief
|
||||||
|
// activity-jitter cannot repeatedly toggle moving/stationary while the user is idle.
|
||||||
|
// (This is ignored on iOS.)
|
||||||
|
motionTriggerDelay: 300000,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
active: {
|
active: {
|
||||||
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
|
geolocation: {
|
||||||
// ACTIVE target: frequent updates while moving.
|
desiredAccuracy: BackgroundGeolocation.DesiredAccuracy.High,
|
||||||
distanceFilter: 25,
|
// ACTIVE target: frequent updates while moving.
|
||||||
|
distanceFilter: 25,
|
||||||
// Never use heartbeat-driven updates; only movement-driven.
|
},
|
||||||
heartbeatInterval: 0,
|
app: {
|
||||||
|
// Never use heartbeat-driven updates; only movement-driven.
|
||||||
// Android-only: do not delay motion triggers while ACTIVE.
|
heartbeatInterval: 0,
|
||||||
motionTriggerDelay: 0,
|
},
|
||||||
|
activity: {
|
||||||
|
// Android-only: do not delay motion triggers while ACTIVE.
|
||||||
|
motionTriggerDelay: 0,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -44,9 +44,9 @@ export async function getCurrentLocation() {
|
||||||
|
|
||||||
const isAuthorized =
|
const isAuthorized =
|
||||||
authorizationStatus ===
|
authorizationStatus ===
|
||||||
BackgroundGeolocation.AUTHORIZATION_STATUS_ALWAYS ||
|
BackgroundGeolocation.AuthorizationStatus?.Always ||
|
||||||
authorizationStatus ===
|
authorizationStatus ===
|
||||||
BackgroundGeolocation.AUTHORIZATION_STATUS_WHEN_IN_USE;
|
BackgroundGeolocation.AuthorizationStatus?.WhenInUse;
|
||||||
|
|
||||||
if (!isAuthorized) {
|
if (!isAuthorized) {
|
||||||
// If unable to get permissions, provide a link to settings
|
// If unable to get permissions, provide a link to settings
|
||||||
|
|
@ -67,7 +67,7 @@ export async function getCurrentLocation() {
|
||||||
timeout: 30,
|
timeout: 30,
|
||||||
persist: false,
|
persist: false,
|
||||||
maximumAge: 5000,
|
maximumAge: 5000,
|
||||||
desiredAccuracy: BackgroundGeolocation.DESIRED_ACCURACY_HIGH,
|
desiredAccuracy: BackgroundGeolocation.DesiredAccuracy.High,
|
||||||
samples: 1,
|
samples: 1,
|
||||||
});
|
});
|
||||||
const coords = camelCaseKeys(location.coords);
|
const coords = camelCaseKeys(location.coords);
|
||||||
|
|
|
||||||
|
|
@ -64,14 +64,16 @@ export default function trackLocation() {
|
||||||
try {
|
try {
|
||||||
const { userId } = getSessionState();
|
const { userId } = getSessionState();
|
||||||
await BackgroundGeolocation.setConfig({
|
await BackgroundGeolocation.setConfig({
|
||||||
extras: {
|
persistence: {
|
||||||
tracking_ctx: {
|
extras: {
|
||||||
reason,
|
tracking_ctx: {
|
||||||
app_state: appState,
|
reason,
|
||||||
profile: currentProfile,
|
app_state: appState,
|
||||||
auth_ready: authReady,
|
profile: currentProfile,
|
||||||
session_user_id: userId || null,
|
auth_ready: authReady,
|
||||||
at: new Date().toISOString(),
|
session_user_id: userId || null,
|
||||||
|
at: new Date().toISOString(),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
@ -249,7 +251,17 @@ export default function trackLocation() {
|
||||||
const AUTH_FIX_COOLDOWN_MS = 15 * 60 * 1000;
|
const AUTH_FIX_COOLDOWN_MS = 15 * 60 * 1000;
|
||||||
let lastAuthFixAt = 0;
|
let lastAuthFixAt = 0;
|
||||||
|
|
||||||
|
// Avoid periodic UI-only getCurrentPosition while app is backgrounded, since
|
||||||
|
// this is a common source of "updates while stationary" (it can also influence
|
||||||
|
// motion state / generate provider churn on some Android devices).
|
||||||
|
const shouldAllowUiFixes = () => appState === "active";
|
||||||
|
|
||||||
const scheduleAuthFreshFix = () => {
|
const scheduleAuthFreshFix = () => {
|
||||||
|
// Do not perform UI refresh fixes while backgrounded.
|
||||||
|
if (!shouldAllowUiFixes()) {
|
||||||
|
return authFixInFlight;
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid generating persisted + auto-synced locations as a side-effect of frequent
|
// Avoid generating persisted + auto-synced locations as a side-effect of frequent
|
||||||
// auth refreshes (eg app resume / screen unlock).
|
// auth refreshes (eg app resume / screen unlock).
|
||||||
if (Date.now() - lastAuthFixAt < AUTH_FIX_COOLDOWN_MS) {
|
if (Date.now() - lastAuthFixAt < AUTH_FIX_COOLDOWN_MS) {
|
||||||
|
|
@ -365,9 +377,9 @@ export default function trackLocation() {
|
||||||
|
|
||||||
locationLogger.info("Applying tracking profile", {
|
locationLogger.info("Applying tracking profile", {
|
||||||
profileName,
|
profileName,
|
||||||
desiredAccuracy: profile.desiredAccuracy,
|
desiredAccuracy: profile?.geolocation?.desiredAccuracy,
|
||||||
distanceFilter: profile.distanceFilter,
|
distanceFilter: profile?.geolocation?.distanceFilter,
|
||||||
heartbeatInterval: profile.heartbeatInterval,
|
heartbeatInterval: profile?.app?.heartbeatInterval,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -485,9 +497,11 @@ export default function trackLocation() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await BackgroundGeolocation.setConfig({
|
await BackgroundGeolocation.setConfig({
|
||||||
url: "",
|
http: {
|
||||||
autoSync: false,
|
url: "",
|
||||||
headers: {},
|
autoSync: false,
|
||||||
|
headers: {},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
didDisableUploadsForAnonymous = true;
|
didDisableUploadsForAnonymous = true;
|
||||||
didSyncAfterAuth = false;
|
didSyncAfterAuth = false;
|
||||||
|
|
@ -547,14 +561,17 @@ export default function trackLocation() {
|
||||||
// unsub();
|
// unsub();
|
||||||
locationLogger.debug("Updating background geolocation config");
|
locationLogger.debug("Updating background geolocation config");
|
||||||
await BackgroundGeolocation.setConfig({
|
await BackgroundGeolocation.setConfig({
|
||||||
url: env.GEOLOC_SYNC_URL, // Update the sync URL for when it's changed for staging
|
http: {
|
||||||
// IMPORTANT: enable native uploading when authenticated.
|
// Update the sync URL for when it's changed for staging
|
||||||
// This ensures uploads continue even if JS is suspended in background.
|
url: env.GEOLOC_SYNC_URL,
|
||||||
autoSync: true,
|
// IMPORTANT: enable native uploading when authenticated.
|
||||||
batchSync: false,
|
// This ensures uploads continue even if JS is suspended in background.
|
||||||
autoSyncThreshold: 0,
|
autoSync: true,
|
||||||
headers: {
|
batchSync: false,
|
||||||
Authorization: `Bearer ${userToken}`,
|
autoSyncThreshold: 0,
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${userToken}`,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -756,11 +773,50 @@ export default function trackLocation() {
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onMotionChange: (event) => {
|
onMotionChange: (event) => {
|
||||||
|
// Diagnostic snapshot to understand periodic motion-change loops (eg Android ~5min).
|
||||||
|
// Keep it cheap: avoid heavy calls unless motion-change fires.
|
||||||
|
// NOTE: This is safe to run in background because it does not request a new location.
|
||||||
locationLogger.info("Motion change", {
|
locationLogger.info("Motion change", {
|
||||||
isMoving: event?.isMoving,
|
isMoving: event?.isMoving,
|
||||||
location: event?.location?.coords,
|
location: event?.location?.coords,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Async snapshot of BGGeo internal state/config at the time of motion-change.
|
||||||
|
// This helps correlate native behavior with our current profile + config.
|
||||||
|
(async () => {
|
||||||
|
try {
|
||||||
|
const state = await BackgroundGeolocation.getState();
|
||||||
|
|
||||||
|
locationLogger.info("Motion change diagnostic", {
|
||||||
|
isMoving: event?.isMoving,
|
||||||
|
appState: appState,
|
||||||
|
profile: currentProfile,
|
||||||
|
authReady,
|
||||||
|
// Time correlation
|
||||||
|
at: new Date().toISOString(),
|
||||||
|
// Core BGGeo runtime state
|
||||||
|
enabled: state?.enabled,
|
||||||
|
trackingMode: state?.trackingMode,
|
||||||
|
isMovingState: state?.isMoving,
|
||||||
|
schedulerEnabled: state?.schedulerEnabled,
|
||||||
|
// Critical config knobs related to periodic updates
|
||||||
|
distanceFilter: state?.geolocation?.distanceFilter,
|
||||||
|
heartbeatInterval: state?.app?.heartbeatInterval,
|
||||||
|
motionTriggerDelay: state?.activity?.motionTriggerDelay,
|
||||||
|
disableMotionActivityUpdates:
|
||||||
|
state?.activity?.disableMotionActivityUpdates,
|
||||||
|
stopTimeout: state?.geolocation?.stopTimeout,
|
||||||
|
// Location quality signal
|
||||||
|
accuracy: event?.location?.coords?.accuracy,
|
||||||
|
speed: event?.location?.coords?.speed,
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
locationLogger.warn("Motion change diagnostic failed", {
|
||||||
|
error: e?.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
// Moving-edge strategy: when we enter moving state, force one persisted high-quality
|
// Moving-edge strategy: when we enter moving state, force one persisted high-quality
|
||||||
// point + sync so the server gets a quick update.
|
// point + sync so the server gets a quick update.
|
||||||
//
|
//
|
||||||
|
|
|
||||||
42
yarn.lock
42
yarn.lock
|
|
@ -3237,6 +3237,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@babel/runtime@npm:^7.26.0":
|
||||||
|
version: 7.28.6
|
||||||
|
resolution: "@babel/runtime@npm:7.28.6"
|
||||||
|
checksum: 10/fbcd439cb74d4a681958eb064c509829e3f46d8a4bfaaf441baa81bb6733d1e680bccc676c813883d7741bcaada1d0d04b15aa320ef280b5734e2192b50decf9
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@babel/template@npm:^7.0.0, @babel/template@npm:^7.22.5":
|
"@babel/template@npm:^7.0.0, @babel/template@npm:^7.22.5":
|
||||||
version: 7.22.5
|
version: 7.22.5
|
||||||
resolution: "@babel/template@npm:7.22.5"
|
resolution: "@babel/template@npm:7.22.5"
|
||||||
|
|
@ -6110,6 +6117,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@transistorsoft/background-geolocation-types@npm:^5.0.1":
|
||||||
|
version: 5.0.1
|
||||||
|
resolution: "@transistorsoft/background-geolocation-types@npm:5.0.1"
|
||||||
|
checksum: 10/14e8a1e64f653f59c8ff22ecb576fc79b632278acdd1bb70a84d938d943f98bd51c620827a0036c4e486e2eaac255101686c40487904b1c866e7e261867faac0
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@turf/along@npm:^7.1.0":
|
"@turf/along@npm:^7.1.0":
|
||||||
version: 7.1.0
|
version: 7.1.0
|
||||||
resolution: "@turf/along@npm:7.1.0"
|
resolution: "@turf/along@npm:7.1.0"
|
||||||
|
|
@ -7127,7 +7141,7 @@ __metadata:
|
||||||
react-native-animatable: "npm:^1.3.3"
|
react-native-animatable: "npm:^1.3.3"
|
||||||
react-native-app-link: "npm:^1.0.1"
|
react-native-app-link: "npm:^1.0.1"
|
||||||
react-native-background-fetch: "npm:^4.2.8"
|
react-native-background-fetch: "npm:^4.2.8"
|
||||||
react-native-background-geolocation: "npm:^4.19.0"
|
react-native-background-geolocation: "npm:^5.0.1"
|
||||||
react-native-battery-optimization-check: "npm:^1.0.8"
|
react-native-battery-optimization-check: "npm:^1.0.8"
|
||||||
react-native-clean-project: "npm:^4.0.3"
|
react-native-clean-project: "npm:^4.0.3"
|
||||||
react-native-contact-pick: "npm:^0.1.2"
|
react-native-contact-pick: "npm:^0.1.2"
|
||||||
|
|
@ -16713,19 +16727,14 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"react-native-background-fetch@npm:~4.2.6":
|
"react-native-background-geolocation@npm:^5.0.1":
|
||||||
version: 4.2.7
|
version: 5.0.1
|
||||||
resolution: "react-native-background-fetch@npm:4.2.7"
|
resolution: "react-native-background-geolocation@npm:5.0.1"
|
||||||
checksum: 10/f0b3d008379dbd992cc1d9708ba1dae86848226a3f4644a8e5955d805841e3122ad56be28bea79af3fa6a03fa5e4f4b8ebf593eacee4dc5ef1ec8cd2dfd5f379
|
|
||||||
languageName: node
|
|
||||||
linkType: hard
|
|
||||||
|
|
||||||
"react-native-background-geolocation@npm:^4.19.0":
|
|
||||||
version: 4.19.0
|
|
||||||
resolution: "react-native-background-geolocation@npm:4.19.0"
|
|
||||||
dependencies:
|
dependencies:
|
||||||
react-native-background-fetch: "npm:~4.2.6"
|
"@babel/runtime": "npm:^7.26.0"
|
||||||
checksum: 10/0ef8a52737ff77b2f04b4c6b1f806abc576b85570c4eba0274e9d2ea0b8393ccd96c7c24c1c5b067f4111b317a958b6d3760dc2a63b733ebecd6af63306a7191
|
"@transistorsoft/background-geolocation-types": "npm:^5.0.1"
|
||||||
|
tslib: "npm:^2.6.3"
|
||||||
|
checksum: 10/7d994a2403228669140ffed55019041d0b2aab08b9de3dd4cbbfb26ea6378488a3c4d5fc0779f6138ddacb796df21363cafab996c0d83a86cd213975c1abc56c
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
|
@ -19092,6 +19101,13 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"tslib@npm:^2.6.3":
|
||||||
|
version: 2.8.1
|
||||||
|
resolution: "tslib@npm:2.8.1"
|
||||||
|
checksum: 10/3e2e043d5c2316461cb54e5c7fe02c30ef6dccb3384717ca22ae5c6b5bc95232a6241df19c622d9c73b809bea33b187f6dbc73030963e29950c2141bc32a79f7
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"tween-functions@npm:^1.0.1":
|
"tween-functions@npm:^1.0.1":
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
resolution: "tween-functions@npm:1.2.0"
|
resolution: "tween-functions@npm:1.2.0"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue