foreground-location 0.0.1

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.
package/README.md ADDED
@@ -0,0 +1,931 @@
1
+ # Capacitor Foreground Location Plugin
2
+
3
+ A robust Capacitor plugin that provides foreground location tracking with optional API service integration. This plugin enables continuous location tracking with a foreground service, real-time updates to your Ionic/Capacitor app, and optional batching of location data to remote API endpoints.
4
+
5
+ ## Features
6
+
7
+ - 🚀 **Foreground Service**: Continuous location tracking with persistent notification
8
+ - 📍 **High Accuracy**: Support for multiple location priority levels
9
+ - 📱 **Real-time Updates**: Live location updates via event listeners
10
+ - 🌐 **API Integration**: Batch and send location data to remote endpoints with retry logic
11
+ - ⚡ **Power Efficient**: Configurable intervals and priorities for battery optimization
12
+ - 🔄 **Resilient API Service**: Circuit breaker pattern and exponential backoff
13
+ - 💾 **Memory Safe**: Configurable buffer management
14
+ - 🛡️ **Permission Management**: Comprehensive permission handling for all platforms
15
+ - 📊 **Service Monitoring**: Real-time service and API status monitoring
16
+ - 🎯 **Cross-platform**: Full support for Android and iOS (web stub implementation)
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install foreground-location
22
+ npx cap sync
23
+ ```
24
+
25
+ ## Platform Setup
26
+
27
+ ### Android Configuration
28
+
29
+ Add the following permissions to your `android/app/src/main/AndroidManifest.xml`:
30
+
31
+ ```xml
32
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
33
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
34
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
35
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
36
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
37
+ <uses-permission android:name="android.permission.INTERNET" />
38
+ ```
39
+
40
+ ### iOS Configuration
41
+
42
+ Add the following to your `ios/App/App/Info.plist`:
43
+
44
+ ```xml
45
+ <key>NSLocationWhenInUseUsageDescription</key>
46
+ <string>This app needs location access to track your location in the foreground</string>
47
+ <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
48
+ <string>This app needs location access to track your location continuously</string>
49
+ <key>UIBackgroundModes</key>
50
+ <array>
51
+ <string>location</string>
52
+ </array>
53
+ ```
54
+
55
+ ## Quick Start
56
+
57
+ ### Basic Location Tracking
58
+
59
+ ```typescript
60
+ import { ForeGroundLocation } from 'foreground-location';
61
+
62
+ // Check and request permissions
63
+ const checkPermissions = async () => {
64
+ const permissions = await ForeGroundLocation.checkPermissions();
65
+
66
+ if (permissions.location !== 'granted') {
67
+ const requested = await ForeGroundLocation.requestPermissions();
68
+ if (requested.location !== 'granted') {
69
+ throw new Error('Location permission required');
70
+ }
71
+ }
72
+ };
73
+
74
+ // Start location tracking
75
+ const startTracking = async () => {
76
+ try {
77
+ await checkPermissions();
78
+
79
+ // Add location listener
80
+ await ForeGroundLocation.addListener('locationUpdate', (location) => {
81
+ console.log('New location:', location);
82
+ // Handle location update in your app
83
+ });
84
+
85
+ // Start the foreground service
86
+ await ForeGroundLocation.startForegroundLocationService({
87
+ interval: 10000, // Update every 10 seconds
88
+ fastestInterval: 5000, // But not faster than 5 seconds
89
+ priority: 'HIGH_ACCURACY',
90
+ notification: {
91
+ title: 'Location Tracking',
92
+ text: 'Tracking your location in the background',
93
+ icon: 'location_on', // Optional: your notification icon
94
+ },
95
+ });
96
+
97
+ console.log('Location tracking started');
98
+ } catch (error) {
99
+ console.error('Failed to start location tracking:', error);
100
+ }
101
+ };
102
+
103
+ // Stop location tracking
104
+ const stopTracking = async () => {
105
+ try {
106
+ await ForeGroundLocation.stopForegroundLocationService();
107
+ await ForeGroundLocation.removeAllListeners();
108
+ console.log('Location tracking stopped');
109
+ } catch (error) {
110
+ console.error('Failed to stop location tracking:', error);
111
+ }
112
+ };
113
+ ```
114
+
115
+ ### Location Tracking with API Integration
116
+
117
+ ```typescript
118
+ import { ForeGroundLocation } from 'foreground-location';
119
+
120
+ const startTrackingWithAPI = async () => {
121
+ try {
122
+ await checkPermissions();
123
+
124
+ // Listen for location updates
125
+ await ForeGroundLocation.addListener('locationUpdate', (location) => {
126
+ console.log('Real-time location:', location);
127
+ // Update your UI immediately
128
+ });
129
+
130
+ // Listen for service status changes
131
+ await ForeGroundLocation.addListener('serviceStatusChanged', (status) => {
132
+ console.log('Service status:', status);
133
+ if (status.error) {
134
+ console.error('Service error:', status.error);
135
+ }
136
+ });
137
+
138
+ // Start tracking with API integration
139
+ await ForeGroundLocation.startForegroundLocationService({
140
+ interval: 30000, // 30 seconds
141
+ fastestInterval: 15000,
142
+ priority: 'HIGH_ACCURACY',
143
+ notification: {
144
+ title: 'Location Tracking Active',
145
+ text: 'Sending location data to server',
146
+ },
147
+ api: {
148
+ url: 'https://api.yourservice.com/locations',
149
+ type: 'POST',
150
+ header: {
151
+ Authorization: 'Bearer your-token',
152
+ 'Content-Type': 'application/json',
153
+ },
154
+ apiInterval: 5, // Send to API every 5 minutes
155
+ additionalParams: {
156
+ userId: 'user123',
157
+ deviceId: 'device456',
158
+ },
159
+ },
160
+ });
161
+
162
+ console.log('Location tracking with API started');
163
+ } catch (error) {
164
+ console.error('Failed to start tracking:', error);
165
+ }
166
+ };
167
+ ```
168
+
169
+ ## API Reference
170
+
171
+ ### Methods
172
+
173
+ #### `checkPermissions(): Promise<LocationPermissionStatus>`
174
+
175
+ Check the current permission status for location services.
176
+
177
+ **Returns:**
178
+
179
+ ```typescript
180
+ interface LocationPermissionStatus {
181
+ location: PermissionState; // 'granted' | 'denied' | 'prompt'
182
+ backgroundLocation: PermissionState; // Android 10+ background location
183
+ notifications: PermissionState; // Android 13+ notification permission
184
+ }
185
+ ```
186
+
187
+ #### `requestPermissions(): Promise<LocationPermissionStatus>`
188
+
189
+ Request location and notification permissions from the user.
190
+
191
+ #### `startForegroundLocationService(options: LocationServiceOptions): Promise<void>`
192
+
193
+ Start the foreground location service with the specified configuration.
194
+
195
+ **Parameters:**
196
+
197
+ ```typescript
198
+ interface LocationServiceOptions {
199
+ interval?: number; // Update interval in ms (default: 60000)
200
+ fastestInterval?: number; // Fastest interval in ms (default: 30000)
201
+ priority?: 'HIGH_ACCURACY' | 'BALANCED_POWER' | 'LOW_POWER' | 'NO_POWER';
202
+ notification: {
203
+ // REQUIRED for foreground service
204
+ title: string; // Notification title
205
+ text: string; // Notification content
206
+ icon?: string; // Optional icon resource name
207
+ };
208
+ enableHighAccuracy?: boolean; // Enable GPS (default: true)
209
+ distanceFilter?: number; // Min distance in meters for updates
210
+ api?: ApiServiceConfig; // Optional API integration
211
+ }
212
+ ```
213
+
214
+ #### `stopForegroundLocationService(): Promise<void>`
215
+
216
+ Stop the foreground location service and clear all location tracking.
217
+
218
+ #### `isServiceRunning(): Promise<{ isRunning: boolean }>`
219
+
220
+ Check if the location service is currently running.
221
+
222
+ #### `getCurrentLocation(): Promise<LocationResult>`
223
+
224
+ Get a single location update without starting the service.
225
+
226
+ **Returns:**
227
+
228
+ ```typescript
229
+ interface LocationResult {
230
+ latitude: number;
231
+ longitude: number;
232
+ accuracy: number;
233
+ altitude?: number;
234
+ bearing?: number;
235
+ speed?: number;
236
+ timestamp: string; // ISO 8601 format
237
+ }
238
+ ```
239
+
240
+ #### `updateLocationSettings(options: LocationServiceOptions): Promise<void>`
241
+
242
+ Update the location service settings while it's running.
243
+
244
+ #### `getApiServiceStatus(): Promise<ApiServiceStatus>`
245
+
246
+ Get the current status of the API service integration.
247
+
248
+ **Returns:**
249
+
250
+ ```typescript
251
+ interface ApiServiceStatus {
252
+ isEnabled: boolean; // API service is configured and active
253
+ bufferSize: number; // Number of locations waiting to be sent
254
+ isHealthy: boolean; // Service is healthy (not in circuit breaker state)
255
+ }
256
+ ```
257
+
258
+ #### `clearApiBuffers(): Promise<void>`
259
+
260
+ Clear all buffered location data waiting to be sent to the API.
261
+
262
+ #### `resetApiCircuitBreaker(): Promise<void>`
263
+
264
+ Reset the API service circuit breaker to allow requests again.
265
+
266
+ ### Event Listeners
267
+
268
+ #### `addListener(eventName: 'locationUpdate', callback: (location: LocationResult) => void): Promise<PluginListenerHandle>`
269
+
270
+ Listen for real-time location updates.
271
+
272
+ #### `addListener(eventName: 'serviceStatusChanged', callback: (status: ServiceStatus) => void): Promise<PluginListenerHandle>`
273
+
274
+ Listen for service status changes.
275
+
276
+ **ServiceStatus:**
277
+
278
+ ```typescript
279
+ interface ServiceStatus {
280
+ isRunning: boolean;
281
+ error?: string; // Error message if service failed
282
+ }
283
+ ```
284
+
285
+ #### `removeAllListeners(): Promise<void>`
286
+
287
+ Remove all event listeners.
288
+
289
+ ### Configuration Interfaces
290
+
291
+ #### `ApiServiceConfig`
292
+
293
+ ```typescript
294
+ interface ApiServiceConfig {
295
+ url: string; // API endpoint URL (REQUIRED)
296
+ type?: 'GET' | 'POST' | 'PUT' | 'PATCH'; // HTTP method (default: 'POST')
297
+ header?: Record<string, string>; // HTTP headers
298
+ additionalParams?: Record<string, any>; // Extra parameters for request body
299
+ apiInterval?: number; // Send interval in minutes (default: 5)
300
+ }
301
+ ```
302
+
303
+ ### Error Handling
304
+
305
+ The plugin provides consistent error codes:
306
+
307
+ ```typescript
308
+ const ERROR_CODES = {
309
+ PERMISSION_DENIED: 'PERMISSION_DENIED',
310
+ INVALID_NOTIFICATION: 'INVALID_NOTIFICATION',
311
+ INVALID_PARAMETERS: 'INVALID_PARAMETERS',
312
+ LOCATION_SERVICES_DISABLED: 'LOCATION_SERVICES_DISABLED',
313
+ UNSUPPORTED_PLATFORM: 'UNSUPPORTED_PLATFORM',
314
+ } as const;
315
+ ```
316
+
317
+ ## Advanced Usage Examples
318
+
319
+ ### Service Monitoring
320
+
321
+ ```typescript
322
+ import { ForeGroundLocation } from 'foreground-location';
323
+
324
+ const monitorLocationService = async () => {
325
+ // Check if service is already running
326
+ const { isRunning } = await ForeGroundLocation.isServiceRunning();
327
+ console.log('Service running:', isRunning);
328
+
329
+ // Monitor API service status
330
+ const apiStatus = await ForeGroundLocation.getApiServiceStatus();
331
+ console.log('API Status:', {
332
+ enabled: apiStatus.isEnabled,
333
+ buffer: apiStatus.bufferSize,
334
+ healthy: apiStatus.isHealthy,
335
+ });
336
+
337
+ // Listen for service status changes
338
+ await ForeGroundLocation.addListener('serviceStatusChanged', (status) => {
339
+ if (status.error) {
340
+ console.error('Service error:', status.error);
341
+ // Handle service errors (restart, notify user, etc.)
342
+ }
343
+ });
344
+ };
345
+ ```
346
+
347
+ ### Power-Optimized Tracking
348
+
349
+ ```typescript
350
+ const startEfficientTracking = async () => {
351
+ await ForeGroundLocation.startForegroundLocationService({
352
+ interval: 120000, // 2 minutes for battery saving
353
+ fastestInterval: 60000, // Minimum 1 minute
354
+ priority: 'BALANCED_POWER', // Balance accuracy and battery
355
+ distanceFilter: 10, // Only update if moved 10+ meters
356
+ enableHighAccuracy: false, // Disable GPS for power saving
357
+ notification: {
358
+ title: 'Efficient Tracking',
359
+ text: 'Battery-optimized location tracking',
360
+ },
361
+ });
362
+ };
363
+ ```
364
+
365
+ ### Dynamic Settings Update
366
+
367
+ ```typescript
368
+ const switchToHighAccuracy = async () => {
369
+ try {
370
+ // Update settings without stopping the service
371
+ await ForeGroundLocation.updateLocationSettings({
372
+ interval: 5000,
373
+ fastestInterval: 2000,
374
+ priority: 'HIGH_ACCURACY',
375
+ enableHighAccuracy: true,
376
+ notification: {
377
+ title: 'High Accuracy Mode',
378
+ text: 'Precise location tracking active',
379
+ },
380
+ });
381
+ console.log('Switched to high accuracy mode');
382
+ } catch (error) {
383
+ console.error('Failed to update settings:', error);
384
+ }
385
+ };
386
+ ```
387
+
388
+ ### API Integration with Error Handling
389
+
390
+ ```typescript
391
+ const robustApiTracking = async () => {
392
+ try {
393
+ await ForeGroundLocation.startForegroundLocationService({
394
+ interval: 30000,
395
+ notification: {
396
+ title: 'Location Sync',
397
+ text: 'Syncing location data to cloud',
398
+ },
399
+ api: {
400
+ url: 'https://api.yourservice.com/locations',
401
+ type: 'POST',
402
+ header: {
403
+ Authorization: 'Bearer ' + (await getAuthToken()),
404
+ 'Content-Type': 'application/json',
405
+ 'X-Device-ID': await getDeviceId(),
406
+ },
407
+ apiInterval: 3, // Send every 3 minutes
408
+ additionalParams: {
409
+ source: 'mobile-app',
410
+ version: '1.0.0',
411
+ },
412
+ },
413
+ });
414
+
415
+ // Monitor API health
416
+ setInterval(async () => {
417
+ const status = await ForeGroundLocation.getApiServiceStatus();
418
+
419
+ if (!status.isHealthy) {
420
+ console.warn('API service unhealthy, resetting...');
421
+ await ForeGroundLocation.resetApiCircuitBreaker();
422
+ }
423
+
424
+ if (status.bufferSize > 50) {
425
+ console.warn('Buffer getting full:', status.bufferSize);
426
+ // Optionally clear old data or adjust settings
427
+ }
428
+ }, 60000); // Check every minute
429
+ } catch (error) {
430
+ console.error('API tracking setup failed:', error);
431
+ }
432
+ };
433
+ ```
434
+
435
+ ## Implementation Patterns
436
+
437
+ ### React/Ionic Hook
438
+
439
+ ```typescript
440
+ import { useEffect, useState } from 'react';
441
+ import { ForeGroundLocation, LocationResult } from 'foreground-location';
442
+
443
+ export const useLocationTracking = () => {
444
+ const [isTracking, setIsTracking] = useState(false);
445
+ const [currentLocation, setCurrentLocation] = useState<LocationResult | null>(null);
446
+ const [error, setError] = useState<string | null>(null);
447
+
448
+ const startTracking = async (options: LocationServiceOptions) => {
449
+ try {
450
+ setError(null);
451
+
452
+ // Check permissions
453
+ const permissions = await ForeGroundLocation.checkPermissions();
454
+ if (permissions.location !== 'granted') {
455
+ const requested = await ForeGroundLocation.requestPermissions();
456
+ if (requested.location !== 'granted') {
457
+ throw new Error('Location permission denied');
458
+ }
459
+ }
460
+
461
+ // Add listeners
462
+ await ForeGroundLocation.addListener('locationUpdate', (location) => {
463
+ setCurrentLocation(location);
464
+ });
465
+
466
+ await ForeGroundLocation.addListener('serviceStatusChanged', (status) => {
467
+ setIsTracking(status.isRunning);
468
+ if (status.error) {
469
+ setError(status.error);
470
+ }
471
+ });
472
+
473
+ // Start service
474
+ await ForeGroundLocation.startForegroundLocationService(options);
475
+ setIsTracking(true);
476
+ } catch (err) {
477
+ setError(err instanceof Error ? err.message : 'Unknown error');
478
+ setIsTracking(false);
479
+ }
480
+ };
481
+
482
+ const stopTracking = async () => {
483
+ try {
484
+ await ForeGroundLocation.stopForegroundLocationService();
485
+ await ForeGroundLocation.removeAllListeners();
486
+ setIsTracking(false);
487
+ setCurrentLocation(null);
488
+ } catch (err) {
489
+ console.error('Failed to stop tracking:', err);
490
+ }
491
+ };
492
+
493
+ // Cleanup on unmount
494
+ useEffect(() => {
495
+ return () => {
496
+ stopTracking();
497
+ };
498
+ }, []);
499
+
500
+ return {
501
+ isTracking,
502
+ currentLocation,
503
+ error,
504
+ startTracking,
505
+ stopTracking,
506
+ };
507
+ };
508
+ ```
509
+
510
+ ### Angular Service
511
+
512
+ ```typescript
513
+ import { Injectable } from '@angular/core';
514
+ import { BehaviorSubject, Observable } from 'rxjs';
515
+ import { ForeGroundLocation, LocationResult, ServiceStatus } from 'foreground-location';
516
+
517
+ @Injectable({
518
+ providedIn: 'root',
519
+ })
520
+ export class LocationTrackingService {
521
+ private locationSubject = new BehaviorSubject<LocationResult | null>(null);
522
+ private statusSubject = new BehaviorSubject<ServiceStatus>({ isRunning: false });
523
+
524
+ public location$: Observable<LocationResult | null> = this.locationSubject.asObservable();
525
+ public status$: Observable<ServiceStatus> = this.statusSubject.asObservable();
526
+
527
+ async startTracking(options: LocationServiceOptions): Promise<void> {
528
+ try {
529
+ // Request permissions
530
+ const permissions = await ForeGroundLocation.requestPermissions();
531
+ if (permissions.location !== 'granted') {
532
+ throw new Error('Location permission required');
533
+ }
534
+
535
+ // Setup listeners
536
+ await ForeGroundLocation.addListener('locationUpdate', (location) => {
537
+ this.locationSubject.next(location);
538
+ });
539
+
540
+ await ForeGroundLocation.addListener('serviceStatusChanged', (status) => {
541
+ this.statusSubject.next(status);
542
+ });
543
+
544
+ // Start service
545
+ await ForeGroundLocation.startForegroundLocationService(options);
546
+ } catch (error) {
547
+ console.error('Failed to start location tracking:', error);
548
+ throw error;
549
+ }
550
+ }
551
+
552
+ async stopTracking(): Promise<void> {
553
+ await ForeGroundLocation.stopForegroundLocationService();
554
+ await ForeGroundLocation.removeAllListeners();
555
+ this.statusSubject.next({ isRunning: false });
556
+ }
557
+
558
+ async getCurrentLocation(): Promise<LocationResult> {
559
+ return await ForeGroundLocation.getCurrentLocation();
560
+ }
561
+
562
+ async getApiStatus(): Promise<ApiServiceStatus> {
563
+ return await ForeGroundLocation.getApiServiceStatus();
564
+ }
565
+ }
566
+ ```
567
+
568
+ ## Best Practices
569
+
570
+ ### Permission Management
571
+
572
+ - Always check permissions before starting location services
573
+ - Handle permission denial gracefully with user-friendly messaging
574
+ - Request permissions in context when user understands why they're needed
575
+
576
+ ### Battery Optimization
577
+
578
+ - Use `BALANCED_POWER` priority for general use cases
579
+ - Increase intervals (60+ seconds) for background tracking
580
+ - Set `distanceFilter` to avoid unnecessary updates
581
+ - Disable `enableHighAccuracy` when precise GPS isn't needed
582
+
583
+ ### API Integration
584
+
585
+ - Use reasonable `apiInterval` values (5-15 minutes)
586
+ - Implement proper authentication token refresh
587
+ - Monitor `bufferSize` to prevent memory issues
588
+ - Handle circuit breaker states appropriately
589
+
590
+ ### Error Handling
591
+
592
+ - Always wrap plugin calls in try-catch blocks
593
+ - Listen for `serviceStatusChanged` events
594
+ - Provide user feedback for service failures
595
+ - Implement retry logic for critical operations
596
+
597
+ ## Troubleshooting
598
+
599
+ ### Common Issues
600
+
601
+ | Issue | Cause | Solution |
602
+ | -------------------- | --------------------------- | ---------------------------------------------------- |
603
+ | Service not starting | Missing notification config | Provide `notification.title` and `notification.text` |
604
+ | Permission denied | User denied location access | Call `requestPermissions()` and handle denial |
605
+ | High battery usage | Too frequent updates | Increase `interval` and use `BALANCED_POWER` |
606
+ | API data not sending | Network/auth issues | Check API status and reset circuit breaker |
607
+ | Location inaccurate | Wrong priority setting | Use `HIGH_ACCURACY` and `enableHighAccuracy: true` |
608
+
609
+ ### Debug Information
610
+
611
+ ```typescript
612
+ // Get comprehensive debug info
613
+ const debugInfo = async () => {
614
+ const permissions = await ForeGroundLocation.checkPermissions();
615
+ const serviceStatus = await ForeGroundLocation.isServiceRunning();
616
+ const apiStatus = await ForeGroundLocation.getApiServiceStatus();
617
+
618
+ console.log('Debug Info:', {
619
+ permissions,
620
+ serviceRunning: serviceStatus.isRunning,
621
+ apiEnabled: apiStatus.isEnabled,
622
+ bufferSize: apiStatus.bufferSize,
623
+ apiHealthy: apiStatus.isHealthy,
624
+ });
625
+ };
626
+ ```
627
+
628
+ ## Platform Differences
629
+
630
+ ### Android
631
+
632
+ - Requires foreground service with persistent notification
633
+ - Background location permission needed for Android 10+
634
+ - Notification permission required for Android 13+
635
+ - Uses Google Play Services Fused Location Provider
636
+
637
+ ### iOS
638
+
639
+ - Uses Core Location framework
640
+ - Requires usage description in Info.plist
641
+ - Background location requires additional entitlements
642
+ - Location accuracy may be limited based on authorization level
643
+
644
+ ### Web
645
+
646
+ - Stub implementation that throws `unavailable` errors
647
+ - Use Capacitor's Geolocation plugin for web support
648
+
649
+ ## Data Privacy
650
+
651
+ ### Location Data Handling
652
+
653
+ - Location data is only stored temporarily in memory buffers
654
+ - API integration sends data to your specified endpoints only
655
+ - No data is sent to plugin developers or third parties
656
+ - Clear buffers regularly to minimize data retention
657
+
658
+ ### Compliance Considerations
659
+
660
+ - Ensure your API endpoints comply with GDPR, CCPA, etc.
661
+ - Implement user consent mechanisms in your app
662
+ - Provide clear privacy notices about location tracking
663
+ - Allow users to opt-out and delete their data
664
+
665
+ ## Performance Monitoring
666
+
667
+ ```typescript
668
+ // Monitor performance metrics
669
+ const monitorPerformance = async () => {
670
+ setInterval(async () => {
671
+ const apiStatus = await ForeGroundLocation.getApiServiceStatus();
672
+ const serviceStatus = await ForeGroundLocation.isServiceRunning();
673
+
674
+ // Log metrics for monitoring
675
+ console.log('Performance Metrics:', {
676
+ timestamp: new Date().toISOString(),
677
+ serviceRunning: serviceStatus.isRunning,
678
+ apiBufferSize: apiStatus.bufferSize,
679
+ memoryUsage: (performance as any).memory?.usedJSHeapSize,
680
+ });
681
+ }, 300000); // Every 5 minutes
682
+ };
683
+ ```
684
+
685
+ ## Migration Guide
686
+
687
+ ### From version 0.0.x to 1.0.x
688
+
689
+ - Update method names to use `startForegroundLocationService()` instead of `startLocationTracking()`
690
+ - Add required `notification` configuration
691
+ - Update API configuration structure
692
+ - Handle new permission states
693
+
694
+ ## Type Definitions
695
+
696
+ ### Interfaces
697
+
698
+ #### LocationPermissionStatus
699
+
700
+ ```typescript
701
+ interface LocationPermissionStatus {
702
+ /**
703
+ * Fine and coarse location permission status
704
+ */
705
+ location: PermissionState;
706
+
707
+ /**
708
+ * Background location permission status (Android 10+)
709
+ */
710
+ backgroundLocation: PermissionState;
711
+
712
+ /**
713
+ * Notification permission status (Android 13+)
714
+ */
715
+ notifications: PermissionState;
716
+ }
717
+ ```
718
+
719
+ #### LocationServiceOptions
720
+
721
+ ```typescript
722
+ interface LocationServiceOptions {
723
+ /**
724
+ * Update interval in milliseconds
725
+ * @default 60000
726
+ * @minimum 1000
727
+ */
728
+ interval?: number;
729
+
730
+ /**
731
+ * Fastest update interval in milliseconds
732
+ * @default 30000
733
+ * @minimum 1000
734
+ */
735
+ fastestInterval?: number;
736
+
737
+ /**
738
+ * Location accuracy priority
739
+ * @default 'HIGH_ACCURACY'
740
+ */
741
+ priority?: 'HIGH_ACCURACY' | 'BALANCED_POWER' | 'LOW_POWER' | 'NO_POWER';
742
+
743
+ /**
744
+ * Notification configuration for foreground service (REQUIRED)
745
+ */
746
+ notification: {
747
+ /**
748
+ * Notification title (REQUIRED)
749
+ */
750
+ title: string;
751
+ /**
752
+ * Notification text/content (REQUIRED)
753
+ */
754
+ text: string;
755
+ /**
756
+ * Optional notification icon resource name
757
+ */
758
+ icon?: string;
759
+ };
760
+
761
+ /**
762
+ * Enable high accuracy mode
763
+ * @default true
764
+ */
765
+ enableHighAccuracy?: boolean;
766
+
767
+ /**
768
+ * Minimum distance in meters to trigger update
769
+ */
770
+ distanceFilter?: number;
771
+
772
+ /**
773
+ * API service configuration (optional)
774
+ * If provided, location data will be sent to the specified API endpoint in batches
775
+ */
776
+ api?: ApiServiceConfig;
777
+ }
778
+ ```
779
+
780
+ #### ApiServiceConfig
781
+
782
+ ```typescript
783
+ interface ApiServiceConfig {
784
+ /**
785
+ * API endpoint URL (REQUIRED if api config is provided)
786
+ */
787
+ url: string;
788
+
789
+ /**
790
+ * HTTP method to use
791
+ * @default 'POST'
792
+ */
793
+ type?: 'GET' | 'POST' | 'PUT' | 'PATCH';
794
+
795
+ /**
796
+ * HTTP headers to include in API requests
797
+ */
798
+ header?: Record<string, string>;
799
+
800
+ /**
801
+ * Additional parameters to include in API request body
802
+ */
803
+ additionalParams?: Record<string, any>;
804
+
805
+ /**
806
+ * Interval in minutes for sending batched location data to API
807
+ * @default 5
808
+ * @minimum 1
809
+ */
810
+ apiInterval?: number;
811
+ }
812
+ ```
813
+
814
+ #### ApiServiceStatus
815
+
816
+ ```typescript
817
+ interface ApiServiceStatus {
818
+ /**
819
+ * Whether API service is enabled and configured
820
+ */
821
+ isEnabled: boolean;
822
+
823
+ /**
824
+ * Number of location points in buffer waiting to be sent
825
+ */
826
+ bufferSize: number;
827
+
828
+ /**
829
+ * Whether API service is healthy (not in circuit breaker state)
830
+ */
831
+ isHealthy: boolean;
832
+ }
833
+ ```
834
+
835
+ #### LocationResult
836
+
837
+ ```typescript
838
+ interface LocationResult {
839
+ /**
840
+ * Latitude in decimal degrees
841
+ */
842
+ latitude: number;
843
+
844
+ /**
845
+ * Longitude in decimal degrees
846
+ */
847
+ longitude: number;
848
+
849
+ /**
850
+ * Accuracy of the location in meters
851
+ */
852
+ accuracy: number;
853
+
854
+ /**
855
+ * Altitude in meters (if available)
856
+ */
857
+ altitude?: number;
858
+
859
+ /**
860
+ * Bearing in degrees (if available)
861
+ */
862
+ bearing?: number;
863
+
864
+ /**
865
+ * Speed in meters per second (if available)
866
+ */
867
+ speed?: number;
868
+
869
+ /**
870
+ * Timestamp in ISO 8601 format
871
+ */
872
+ timestamp: string;
873
+ }
874
+ ```
875
+
876
+ #### ServiceStatus
877
+
878
+ ```typescript
879
+ interface ServiceStatus {
880
+ /**
881
+ * Whether the service is currently running
882
+ */
883
+ isRunning: boolean;
884
+
885
+ /**
886
+ * Error message if service failed
887
+ */
888
+ error?: string;
889
+ }
890
+ ```
891
+
892
+ ### Type Aliases
893
+
894
+ #### PermissionState
895
+
896
+ ```typescript
897
+ type PermissionState = 'prompt' | 'prompt-with-rationale' | 'granted' | 'denied';
898
+ ```
899
+
900
+ #### ErrorCode
901
+
902
+ ```typescript
903
+ type ErrorCode =
904
+ | 'PERMISSION_DENIED'
905
+ | 'INVALID_NOTIFICATION'
906
+ | 'INVALID_PARAMETERS'
907
+ | 'LOCATION_SERVICES_DISABLED'
908
+ | 'UNSUPPORTED_PLATFORM';
909
+ ```
910
+
911
+ #### PluginListenerHandle
912
+
913
+ ```typescript
914
+ interface PluginListenerHandle {
915
+ remove: () => Promise<void>;
916
+ }
917
+ ```
918
+
919
+ ## Support
920
+
921
+ - **GitHub Issues**: [Report bugs and feature requests](https://github.com/xconcepts17/foreground-location/issues)
922
+ - **Documentation**: [Complete setup guide](./docs/setup-and-examples.md)
923
+ - **Examples**: [Implementation examples](./docs/setup-and-examples.md#complete-implementation-example)
924
+
925
+ ## License
926
+
927
+ MIT License - see [LICENSE](./LICENSE) file for details.
928
+
929
+ ## Contributing
930
+
931
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for contribution guidelines and development setup.