@kafitra/react-native-live-tracking 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +396 -0
  3. package/android/build.gradle +71 -0
  4. package/android/gradle.properties +7 -0
  5. package/android/src/main/AndroidManifest.xml +40 -0
  6. package/android/src/main/java/com/livetracking/LiveTrackingModuleImpl.kt +728 -0
  7. package/android/src/main/java/com/livetracking/LiveTrackingPackage.kt +16 -0
  8. package/android/src/main/java/com/livetracking/location/LocationEngine.kt +93 -0
  9. package/android/src/main/java/com/livetracking/network/NetworkListener.kt +127 -0
  10. package/android/src/main/java/com/livetracking/optimizer/ActivityRecognitionHandler.kt +248 -0
  11. package/android/src/main/java/com/livetracking/optimizer/MotionSleepManager.kt +130 -0
  12. package/android/src/main/java/com/livetracking/permissions/PermissionHandler.kt +145 -0
  13. package/android/src/main/java/com/livetracking/queue/QueueEngine.kt +167 -0
  14. package/android/src/main/java/com/livetracking/queue/QueuedLocation.kt +16 -0
  15. package/android/src/main/java/com/livetracking/queue/TrackingDatabase.kt +239 -0
  16. package/android/src/main/java/com/livetracking/receiver/BootReceiver.kt +53 -0
  17. package/android/src/main/java/com/livetracking/service/TrackingForegroundService.kt +145 -0
  18. package/android/src/main/java/com/livetracking/sync/FirebaseSyncEngine.kt +277 -0
  19. package/android/src/main/java/com/livetracking/sync/LocationDataPoint.kt +31 -0
  20. package/android/src/main/java/com/livetracking/sync/SyncEngineController.kt +220 -0
  21. package/android/src/main/java/com/livetracking/sync/SyncTargetConfig.kt +20 -0
  22. package/android/src/main/java/com/livetracking/sync/TargetHandler.kt +601 -0
  23. package/android/src/newarch/java/com/livetracking/LiveTrackingModule.kt +64 -0
  24. package/android/src/oldarch/java/com/livetracking/LiveTrackingModule.kt +70 -0
  25. package/android/src/test/java/com/livetracking/BackoffCalculationTest.kt +216 -0
  26. package/android/src/test/java/com/livetracking/BatchAccumulatorTest.kt +391 -0
  27. package/android/src/test/java/com/livetracking/BootReceiverTest.kt +247 -0
  28. package/android/src/test/java/com/livetracking/FirebaseSyncEngineTest.kt +337 -0
  29. package/android/src/test/java/com/livetracking/LocationEngineTest.kt +202 -0
  30. package/android/src/test/java/com/livetracking/MotionSleepManagerTest.kt +420 -0
  31. package/android/src/test/java/com/livetracking/OfflineQueueTest.kt +462 -0
  32. package/android/src/test/java/com/livetracking/PermissionHandlerTest.kt +200 -0
  33. package/android/src/test/java/com/livetracking/QueueEngineTest.kt +335 -0
  34. package/android/src/test/java/com/livetracking/SyncEngineControllerTest.kt +855 -0
  35. package/ios/ActivityRecognitionHandler.swift +196 -0
  36. package/ios/BackgroundModeHelper.swift +132 -0
  37. package/ios/FirebaseSyncEngine.swift +276 -0
  38. package/ios/LiveTracking-Bridging-Header.h +2 -0
  39. package/ios/LiveTracking.m +37 -0
  40. package/ios/LiveTracking.swift +773 -0
  41. package/ios/LocationDataPoint.swift +56 -0
  42. package/ios/LocationEngine.swift +160 -0
  43. package/ios/MotionSleepManager.swift +151 -0
  44. package/ios/NetworkListener.swift +105 -0
  45. package/ios/OfflineQueueManager.swift +503 -0
  46. package/ios/PermissionHandler.swift +148 -0
  47. package/ios/QueueEngine.swift +249 -0
  48. package/ios/SyncEngineController.swift +396 -0
  49. package/ios/SyncTargetConfig.swift +36 -0
  50. package/ios/TargetHandler.swift +715 -0
  51. package/ios/Tests/ActivityRecognitionHandlerTests.swift +259 -0
  52. package/ios/Tests/FirebaseSyncEngineTests.swift +303 -0
  53. package/ios/Tests/LocationEngineTests.swift +244 -0
  54. package/ios/Tests/MotionSleepManagerTests.swift +355 -0
  55. package/ios/Tests/NetworkListenerTests.swift +188 -0
  56. package/ios/Tests/OfflineQueueFlushTests.swift +375 -0
  57. package/ios/Tests/PermissionHandlerTests.swift +238 -0
  58. package/ios/Tests/QueueEngineTests.swift +346 -0
  59. package/ios/TrackingCleanup.swift +93 -0
  60. package/ios/TrackingNotificationManager.swift +187 -0
  61. package/lib/commonjs/EventEmitter.js +113 -0
  62. package/lib/commonjs/EventEmitter.js.map +1 -0
  63. package/lib/commonjs/LiveTracking.js +134 -0
  64. package/lib/commonjs/LiveTracking.js.map +1 -0
  65. package/lib/commonjs/NativeLiveTracking.js +21 -0
  66. package/lib/commonjs/NativeLiveTracking.js.map +1 -0
  67. package/lib/commonjs/filters/distanceTimeFilter.js +63 -0
  68. package/lib/commonjs/filters/distanceTimeFilter.js.map +1 -0
  69. package/lib/commonjs/index.js +103 -0
  70. package/lib/commonjs/index.js.map +1 -0
  71. package/lib/commonjs/serialization/locationSerializer.js +51 -0
  72. package/lib/commonjs/serialization/locationSerializer.js.map +1 -0
  73. package/lib/commonjs/types.js +77 -0
  74. package/lib/commonjs/types.js.map +1 -0
  75. package/lib/commonjs/utils/distance.js +63 -0
  76. package/lib/commonjs/utils/distance.js.map +1 -0
  77. package/lib/commonjs/utils/retry.js +80 -0
  78. package/lib/commonjs/utils/retry.js.map +1 -0
  79. package/lib/commonjs/validation.js +463 -0
  80. package/lib/commonjs/validation.js.map +1 -0
  81. package/lib/module/EventEmitter.js +105 -0
  82. package/lib/module/EventEmitter.js.map +1 -0
  83. package/lib/module/LiveTracking.js +127 -0
  84. package/lib/module/LiveTracking.js.map +1 -0
  85. package/lib/module/NativeLiveTracking.js +16 -0
  86. package/lib/module/NativeLiveTracking.js.map +1 -0
  87. package/lib/module/filters/distanceTimeFilter.js +58 -0
  88. package/lib/module/filters/distanceTimeFilter.js.map +1 -0
  89. package/lib/module/index.js +32 -0
  90. package/lib/module/index.js.map +1 -0
  91. package/lib/module/serialization/locationSerializer.js +45 -0
  92. package/lib/module/serialization/locationSerializer.js.map +1 -0
  93. package/lib/module/types.js +94 -0
  94. package/lib/module/types.js.map +1 -0
  95. package/lib/module/utils/distance.js +56 -0
  96. package/lib/module/utils/distance.js.map +1 -0
  97. package/lib/module/utils/retry.js +72 -0
  98. package/lib/module/utils/retry.js.map +1 -0
  99. package/lib/module/validation.js +456 -0
  100. package/lib/module/validation.js.map +1 -0
  101. package/lib/typescript/EventEmitter.d.ts +65 -0
  102. package/lib/typescript/EventEmitter.d.ts.map +1 -0
  103. package/lib/typescript/LiveTracking.d.ts +23 -0
  104. package/lib/typescript/LiveTracking.d.ts.map +1 -0
  105. package/lib/typescript/NativeLiveTracking.d.ts +25 -0
  106. package/lib/typescript/NativeLiveTracking.d.ts.map +1 -0
  107. package/lib/typescript/filters/distanceTimeFilter.d.ts +44 -0
  108. package/lib/typescript/filters/distanceTimeFilter.d.ts.map +1 -0
  109. package/lib/typescript/index.d.ts +21 -0
  110. package/lib/typescript/index.d.ts.map +1 -0
  111. package/lib/typescript/serialization/locationSerializer.d.ts +39 -0
  112. package/lib/typescript/serialization/locationSerializer.d.ts.map +1 -0
  113. package/lib/typescript/types.d.ts +217 -0
  114. package/lib/typescript/types.d.ts.map +1 -0
  115. package/lib/typescript/utils/distance.d.ts +38 -0
  116. package/lib/typescript/utils/distance.d.ts.map +1 -0
  117. package/lib/typescript/utils/retry.d.ts +60 -0
  118. package/lib/typescript/utils/retry.d.ts.map +1 -0
  119. package/lib/typescript/validation.d.ts +26 -0
  120. package/lib/typescript/validation.d.ts.map +1 -0
  121. package/package.json +126 -0
  122. package/react-native-live-tracking.podspec +47 -0
  123. package/src/EventEmitter.ts +118 -0
  124. package/src/LiveTracking.ts +159 -0
  125. package/src/NativeLiveTracking.ts +29 -0
  126. package/src/filters/distanceTimeFilter.ts +75 -0
  127. package/src/index.ts +51 -0
  128. package/src/serialization/locationSerializer.ts +57 -0
  129. package/src/types.ts +252 -0
  130. package/src/utils/distance.ts +68 -0
  131. package/src/utils/retry.ts +75 -0
  132. package/src/validation.ts +552 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kafitra Marna Ibrahim
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,396 @@
1
+ # @kafitra/react-native-live-tracking
2
+
3
+ Real-time location tracking library for React Native with Firebase synchronization. Supports background tracking, offline caching, battery optimization, and fully flexible sync targets.
4
+
5
+ ## Features
6
+
7
+ - **Background Location Tracking** — Android Foreground Service & iOS Background Modes
8
+ - **Flexible Firebase Sync** — Define unlimited sync targets with custom paths, write methods, and behavior
9
+ - **Offline-First** — Per-target offline queue with automatic sync when connection restores
10
+ - **Battery Optimization** — Distance/Time matrix filter + Motion Sleep Mode
11
+ - **Auto-Restart** — Resume tracking after device reboot (Android BOOT_COMPLETED)
12
+ - **Cross-Platform** — iOS 13+ & Android API 21+
13
+ - **New Architecture Ready** — Works with both TurboModules (New Arch) and legacy Bridge (Old Arch) via interop
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @kafitra/react-native-live-tracking
19
+ # or
20
+ yarn add @kafitra/react-native-live-tracking
21
+ ```
22
+
23
+ ### iOS
24
+
25
+ #### 1. Podfile Setup
26
+
27
+ This library depends on `FirebaseDatabase` and `FirebaseFirestore`. If you use `react-native-firebase`, add the required modular headers and permissions in your `Podfile`:
28
+
29
+ ```ruby
30
+ $RNFirebaseAsStaticFramework = true
31
+
32
+ require Pod::Executable.execute_command('node', ['-p',
33
+ 'require.resolve(
34
+ "react-native/scripts/react_native_pods.rb",
35
+ {paths: [process.argv[1]]},
36
+ )', __dir__]).strip
37
+
38
+ require_relative '../node_modules/react-native-permissions/scripts/setup'
39
+
40
+ platform :ios, min_ios_version_supported
41
+ prepare_react_native_project!
42
+
43
+ target 'YourApp' do
44
+ # Firebase modular headers (required for Swift static library integration)
45
+ pod 'GoogleUtilities', :modular_headers => true
46
+ pod 'FirebaseCore', :modular_headers => true
47
+ pod 'FirebaseCoreExtension', :modular_headers => true
48
+ pod 'FirebaseCoreInternal', :modular_headers => true
49
+ pod 'FirebaseAppCheckInterop', :modular_headers => true
50
+ pod 'FirebaseDatabase', :modular_headers => true
51
+ pod 'FirebaseFirestore', :modular_headers => true
52
+ pod 'FirebaseFirestoreInternal', :modular_headers => true
53
+ pod 'leveldb-library', :modular_headers => true
54
+
55
+ # Permissions required by live-tracking
56
+ setup_permissions([
57
+ 'LocationAlways',
58
+ 'LocationWhenInUse',
59
+ 'Motion',
60
+ ])
61
+
62
+ config = use_native_modules!
63
+ use_react_native!(:path => config[:reactNativePath])
64
+ end
65
+ ```
66
+
67
+ #### 2. Install Pods
68
+
69
+ ```bash
70
+ cd ios && pod install
71
+ ```
72
+
73
+ ## Quick Start
74
+
75
+ ```typescript
76
+ import LiveTracking from '@kafitra/react-native-live-tracking';
77
+
78
+ // 1. Configure
79
+ await LiveTracking.configure({
80
+ optimization: {
81
+ intervalMs: 10000, // Minimum 10 seconds between updates
82
+ distanceFilterMeters: 10, // Only update if moved 10+ meters
83
+ stopWhenStill: true, // Save battery when stationary
84
+ },
85
+ androidNotification: {
86
+ title: "Recording Trip",
87
+ text: "Your location is being shared.",
88
+ },
89
+ firebase: {
90
+ service: 'RTDB', // or 'Firestore'
91
+ targets: [
92
+ {
93
+ path: `users/${userId}/current_location`,
94
+ method: 'set', // overwrite — for real-time map marker
95
+ },
96
+ {
97
+ path: `users/${userId}/location_history`,
98
+ method: 'push', // append — for track history
99
+ batchSize: 15, // send every 15 points
100
+ offlineQueue: true, // persist offline if no connection
101
+ },
102
+ ],
103
+ },
104
+ });
105
+
106
+ // 2. Listen for updates
107
+ const subscription = LiveTracking.onLocationUpdate((location) => {
108
+ console.log(location.latitude, location.longitude);
109
+ });
110
+
111
+ // 3. Start tracking
112
+ await LiveTracking.start();
113
+
114
+ // 4. Stop when done
115
+ await LiveTracking.stop();
116
+ subscription.remove();
117
+ ```
118
+
119
+ ## Usage with React Native (TrackingProvider Pattern)
120
+
121
+ A common pattern is to wrap tracking in a provider that reacts to backend status changes (e.g., via Firebase RTDB):
122
+
123
+ ```typescript
124
+ import React, { useEffect } from 'react';
125
+ import LiveTracking from '@kafitra/react-native-live-tracking';
126
+ import database from '@react-native-firebase/database';
127
+
128
+ const TRACKING_STATUS = { READY: 0, ON_PROGRESS: 1, COMPLETED: 2 } as const;
129
+
130
+ async function startLiveTracking(deliveryNoteId: string | number) {
131
+ await LiveTracking.configure({
132
+ firebase: {
133
+ service: 'RTDB',
134
+ targets: [
135
+ { path: `delivery/${deliveryNoteId}/current`, method: 'set' },
136
+ { path: `delivery/${deliveryNoteId}/history`, method: 'push', batchSize: 10, offlineQueue: true },
137
+ ],
138
+ },
139
+ optimization: { intervalMs: 10000, distanceFilterMeters: 10, stopWhenStill: true },
140
+ androidNotification: {
141
+ title: 'Delivery In Progress',
142
+ text: 'Tracking your location...',
143
+ },
144
+ });
145
+ await LiveTracking.start();
146
+ }
147
+
148
+ export function TrackingProvider({ children }: { children: React.ReactNode }) {
149
+ useEffect(() => {
150
+ const statusRef = database().ref(`delivery/188/status`);
151
+ const onValue = statusRef.on('value', (snapshot) => {
152
+ const status = snapshot.val();
153
+ if (status === TRACKING_STATUS.ON_PROGRESS) {
154
+ startLiveTracking(188).catch(console.warn);
155
+ } else if (status === TRACKING_STATUS.COMPLETED) {
156
+ LiveTracking.stop().catch(console.warn);
157
+ }
158
+ });
159
+ return () => statusRef.off('value', onValue);
160
+ }, []);
161
+
162
+ return <>{children}</>;
163
+ }
164
+ ```
165
+
166
+ ## Sync Targets
167
+
168
+ Each sync target defines a **path**, **method**, and optional behavior. You have full control over your Firebase database structure.
169
+
170
+ ```typescript
171
+ interface SyncTarget {
172
+ /** Firebase path to write to */
173
+ path: string;
174
+ /** Write method: 'set' (overwrite), 'push' (append), 'update' (merge) */
175
+ method: 'set' | 'push' | 'update';
176
+ /** Number of points to accumulate before writing. Default: 1 (immediate) */
177
+ batchSize?: number;
178
+ /** Whether to persist data offline when there is no connection. Default: false */
179
+ offlineQueue?: boolean;
180
+ }
181
+ ```
182
+
183
+ ### Write Methods
184
+
185
+ | Method | Behavior | Use Case |
186
+ |--------|----------|----------|
187
+ | `set` | Overwrite data at path | Real-time map marker |
188
+ | `push` | Append with auto-generated key | Track history |
189
+ | `update` | Merge fields without removing existing ones | Partial data update |
190
+
191
+ ### Example: Multiple Targets
192
+
193
+ ```typescript
194
+ firebase: {
195
+ service: 'Firestore',
196
+ targets: [
197
+ // Real-time marker (overwrite, no queue)
198
+ { path: `drivers/${driverId}/location`, method: 'set' },
199
+
200
+ // Trip history (batch + offline queue)
201
+ { path: `trips/${tripId}/points`, method: 'push', batchSize: 20, offlineQueue: true },
202
+
203
+ // Status update (merge into existing document)
204
+ { path: `drivers/${driverId}/status`, method: 'update' },
205
+ ],
206
+ }
207
+ ```
208
+
209
+ ## Configuration
210
+
211
+ ### Optimization
212
+
213
+ | Parameter | Type | Default | Description |
214
+ |-----------|------|---------|-------------|
215
+ | `optimization.intervalMs` | number | 10000 | Minimum interval between updates (ms) |
216
+ | `optimization.distanceFilterMeters` | number | 10 | Minimum distance to trigger update (meters) |
217
+ | `optimization.stopWhenStill` | boolean | true | Enable Motion Sleep Mode |
218
+ | `optimization.mode` | `'interval' \| 'distance' \| 'both'` | `'both'` | Filter strategy: time only, distance only, or both |
219
+
220
+ ### Firebase
221
+
222
+ | Parameter | Type | Required | Description |
223
+ |-----------|------|----------|-------------|
224
+ | `firebase.service` | `'RTDB' \| 'Firestore'` | ✅ | Firebase service type |
225
+ | `firebase.targets` | `SyncTarget[]` | ✅ | Array of sync targets (min 1, max 20) |
226
+
227
+ ### SyncTarget Options
228
+
229
+ | Parameter | Type | Default | Description |
230
+ |-----------|------|---------|-------------|
231
+ | `path` | string | — | Firebase path (1–768 characters) |
232
+ | `method` | `'set' \| 'push' \| 'update'` | — | Write method |
233
+ | `batchSize` | number | 1 | Points per batch (1–1000) |
234
+ | `offlineQueue` | boolean | false | Persist data offline when no connection |
235
+
236
+ ### Android Notification
237
+
238
+ | Parameter | Type | Default | Description |
239
+ |-----------|------|---------|-------------|
240
+ | `androidNotification.enabled` | boolean | `true` | Show the foreground service notification |
241
+ | `androidNotification.title` | string | — | Foreground service notification title (required when enabled) |
242
+ | `androidNotification.text` | string | — | Notification text (required when enabled) |
243
+ | `androidNotification.icon` | string? | — | Icon resource name |
244
+ | `androidNotification.channelId` | string? | — | Notification channel ID |
245
+ | `androidNotification.channelName` | string? | — | Notification channel name |
246
+
247
+ > **Note:** Android requires a foreground service notification to run background tracking. When `enabled: false`, the service still runs but shows a minimal default notification.
248
+
249
+ ### iOS Notification
250
+
251
+ | Parameter | Type | Default | Description |
252
+ |-----------|------|---------|-------------|
253
+ | `iosNotification.enabled` | boolean | `true` | Show the persistent local notification |
254
+ | `iosNotification.title` | string | — | Notification title (required when enabled) |
255
+ | `iosNotification.text` | string | — | Notification body (required when enabled) |
256
+
257
+ ## How It Works
258
+
259
+ ### Distance/Time Matrix
260
+ The filtering strategy is controlled by `optimization.mode`:
261
+
262
+ | Mode | Behavior |
263
+ |------|----------|
264
+ | `both` (default) | Update only when **both** time and distance conditions are met |
265
+ | `interval` | Update only when time since last update ≥ `intervalMs` |
266
+ | `distance` | Update only when distance from last location ≥ `distanceFilterMeters` |
267
+
268
+ ### GPS Disabled During Tracking
269
+ The library monitors GPS/location service status. If GPS is disabled while tracking is active:
270
+ - Tracking is automatically paused
271
+ - An `onError` event with code `GPS_DISABLED` is emitted
272
+ - When GPS is re-enabled, tracking automatically resumes
273
+ - A `GPS_ENABLED` event is emitted on resume
274
+
275
+ ### Motion Sleep Mode
276
+ When `stopWhenStill: true` and device is stationary for > 3 minutes:
277
+ - GPS accuracy is reduced to save battery
278
+ - Resumes full accuracy when movement is detected
279
+
280
+ ### Per-Target Batch Processing
281
+ - Targets with `batchSize > 1` accumulate points in memory
282
+ - Written to Firebase in a single batch operation when full
283
+ - Partial batches are automatically flushed on `stop()` or after 30 seconds of inactivity
284
+
285
+ ### Per-Target Offline Queue
286
+ - Targets with `offlineQueue: true` persist data to SQLite (Android) / CoreData (iOS) when offline
287
+ - Automatically synced when connection restores (chronological order, oldest first)
288
+ - Maximum 10,000 data points per target (oldest evicted when full)
289
+ - Data persists across app restart and process termination
290
+
291
+ ### Retry with Exponential Backoff
292
+ - Each target retries independently (does not block other targets)
293
+ - `set`/`update`: max 3 retries
294
+ - `push`: max 5 retries
295
+ - Base delay 1000ms, multiplier 2x, jitter ±200ms
296
+ - Non-transient errors (permission denied) fail immediately without retry
297
+
298
+ ## Platform Setup
299
+
300
+ ### Android
301
+
302
+ #### Permissions
303
+
304
+ Add to `AndroidManifest.xml`:
305
+ ```xml
306
+ <!-- Location -->
307
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
308
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
309
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
310
+
311
+ <!-- Foreground Service (required for background tracking notification) -->
312
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
313
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
314
+
315
+ <!-- Optional: Notification permission (Android 13+) -->
316
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
317
+
318
+ <!-- Optional: Auto-restart tracking after device reboot -->
319
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
320
+
321
+ <!-- Optional: Motion Sleep Mode (reduce battery when stationary) -->
322
+ <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
323
+
324
+ <!-- Network state detection for offline queue sync -->
325
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
326
+ ```
327
+
328
+ > **Note:** You must request runtime permissions (`ACCESS_FINE_LOCATION`, `ACCESS_BACKGROUND_LOCATION`, `POST_NOTIFICATIONS`) before calling `LiveTracking.start()`. The library will reject with `PERMISSION_DENIED` if required permissions are not granted.
329
+
330
+ #### Firebase Setup
331
+
332
+ Ensure your app has `google-services.json` in `android/app/` and the Google Services plugin applied in your `android/app/build.gradle`:
333
+ ```groovy
334
+ apply plugin: 'com.google.gms.google-services'
335
+ ```
336
+
337
+ ### iOS
338
+
339
+ #### Info.plist
340
+
341
+ Add the following keys to your `Info.plist`:
342
+ ```xml
343
+ <!-- Required: Location permission descriptions -->
344
+ <key>NSLocationWhenInUseUsageDescription</key>
345
+ <string>App needs your location to track deliveries in real-time.</string>
346
+ <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
347
+ <string>App needs background location access to track deliveries while the app is in the background.</string>
348
+
349
+ <!-- Optional: Motion permission for stopWhenStill battery optimization -->
350
+ <key>NSMotionUsageDescription</key>
351
+ <string>Used to optimize battery usage when stationary.</string>
352
+
353
+ <!-- Required: Enable background location updates -->
354
+ <key>UIBackgroundModes</key>
355
+ <array>
356
+ <string>location</string>
357
+ </array>
358
+ ```
359
+
360
+ #### Firebase Setup
361
+
362
+ Ensure your app has `GoogleService-Info.plist` added to the Xcode project.
363
+
364
+ ## API Reference
365
+
366
+ | Method | Returns | Description |
367
+ |--------|---------|-------------|
368
+ | `configure(config)` | `Promise<void>` | Configure the library |
369
+ | `start()` | `Promise<void>` | Start tracking |
370
+ | `stop()` | `Promise<void>` | Stop tracking (flushes all batches) |
371
+ | `getStatus()` | `Promise<TrackingStatus>` | Get current tracking status |
372
+ | `getQueuedLocations()` | `Promise<number>` | Get total offline queue count |
373
+ | `getQueuedLocationsByTarget()` | `Promise<Record<string, number>>` | Get queue count per target path |
374
+ | `onLocationUpdate(cb)` | `Subscription` | Listen for location updates |
375
+ | `onError(cb)` | `Subscription` | Listen for errors |
376
+
377
+ ## Error Codes
378
+
379
+ | Code | Description |
380
+ |------|-------------|
381
+ | `PERMISSION_DENIED` | Location permission not granted |
382
+ | `GPS_DISABLED` | GPS/Location services turned off |
383
+ | `GPS_ENABLED` | GPS/Location services turned back on (auto-resume) |
384
+ | `PERMISSION_REVOKED` | Permission revoked while tracking was paused |
385
+ | `INVALID_CONFIG` | Invalid configuration parameters |
386
+ | `NOT_CONFIGURED` | Method called before `configure()` |
387
+ | `FIREBASE_WRITE_FAILED` | Firebase write failed after max retries |
388
+ | `DEPRECATED_FIELD` | Using old config fields (currentLocationPath/historyPath) |
389
+ | `QUEUE_OVERFLOW` | Offline queue reached 10,000 cap (oldest evicted) |
390
+ | `LOCATION_UNKNOWN` | Location temporarily unavailable |
391
+ | `NETWORK_ERROR` | Location network error |
392
+ | `LOCATION_ERROR` | Generic location update failure |
393
+
394
+ ## License
395
+
396
+ MIT
@@ -0,0 +1,71 @@
1
+ buildscript {
2
+ ext.safeExtGet = {prop, fallback ->
3
+ rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
4
+ }
5
+ }
6
+
7
+ apply plugin: 'com.android.library'
8
+ apply plugin: 'kotlin-android'
9
+ apply plugin: 'com.facebook.react'
10
+
11
+ android {
12
+ namespace "com.livetracking"
13
+
14
+ compileSdkVersion safeExtGet('compileSdkVersion', 34)
15
+
16
+ defaultConfig {
17
+ minSdkVersion safeExtGet('minSdkVersion', 23)
18
+ targetSdkVersion safeExtGet('targetSdkVersion', 34)
19
+ }
20
+
21
+ buildFeatures {
22
+ buildConfig true
23
+ }
24
+
25
+ buildTypes {
26
+ release {
27
+ minifyEnabled false
28
+ }
29
+ }
30
+
31
+ compileOptions {
32
+ sourceCompatibility JavaVersion.VERSION_17
33
+ targetCompatibility JavaVersion.VERSION_17
34
+ }
35
+
36
+ kotlinOptions {
37
+ jvmTarget = '17'
38
+ }
39
+
40
+ sourceSets {
41
+ main {
42
+ java.srcDirs += 'src/main/java'
43
+ java.srcDirs += 'src/oldarch/java'
44
+ }
45
+ }
46
+
47
+ testOptions {
48
+ unitTests {
49
+ includeAndroidResources = true
50
+ }
51
+ }
52
+ }
53
+
54
+ repositories {
55
+ mavenCentral()
56
+ google()
57
+ }
58
+
59
+ dependencies {
60
+ implementation "com.facebook.react:react-android:+"
61
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:${safeExtGet('kotlinVersion', '1.8.22')}"
62
+ implementation "androidx.core:core-ktx:1.12.0"
63
+ implementation "com.google.android.gms:play-services-location:21.0.1"
64
+ implementation "com.google.firebase:firebase-database:20.3.0"
65
+ implementation "com.google.firebase:firebase-firestore:24.10.0"
66
+
67
+ testImplementation "junit:junit:4.13.2"
68
+ testImplementation "io.mockk:mockk:1.13.8"
69
+ testImplementation "org.robolectric:robolectric:4.11.1"
70
+ testImplementation "androidx.test:core:1.5.0"
71
+ }
@@ -0,0 +1,7 @@
1
+ LiveTracking_kotlinVersion=1.8.22
2
+ LiveTracking_compileSdkVersion=34
3
+ LiveTracking_minSdkVersion=23
4
+ LiveTracking_targetSdkVersion=34
5
+ # Enable/disable new architecture (TurboModules)
6
+ # Set to true in consumer app's gradle.properties to enable new architecture
7
+ newArchEnabled=false
@@ -0,0 +1,40 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.livetracking">
3
+
4
+ <!-- Location permissions -->
5
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
6
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
7
+ <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
8
+
9
+ <!-- Foreground service permissions -->
10
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
11
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
12
+
13
+ <!-- Network state permission for connectivity monitoring -->
14
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
15
+
16
+ <!-- Boot completed permission for auto-restart tracking -->
17
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
18
+
19
+ <!-- Activity Recognition permissions for motion detection -->
20
+ <uses-permission android:name="com.google.android.gms.permission.ACTIVITY_RECOGNITION" />
21
+ <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
22
+
23
+ <application>
24
+ <service
25
+ android:name=".service.TrackingForegroundService"
26
+ android:enabled="true"
27
+ android:exported="false"
28
+ android:foregroundServiceType="location" />
29
+
30
+ <receiver
31
+ android:name=".receiver.BootReceiver"
32
+ android:enabled="true"
33
+ android:exported="true">
34
+ <intent-filter>
35
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
36
+ </intent-filter>
37
+ </receiver>
38
+ </application>
39
+
40
+ </manifest>