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.
@@ -0,0 +1,2851 @@
1
+ # Setup and Examples Guide
2
+
3
+ This comprehensive guide provides detailed setup instructions and practical examples for the Capacitor Foreground Location plugin. Learn how to implement location tracking with foreground services and optional API integration.
4
+
5
+ ## Table of Contents
6
+
7
+ - [Installation and Setup](#installation-and-setup)
8
+ - [Permission Management](#permission-management)
9
+ - [Basic Implementation](#basic-implementation)
10
+ - [Advanced Features](#advanced-features)
11
+ - [API Integration Examples](#api-integration-examples)
12
+ - [Framework-Specific Examples](#framework-specific-examples)
13
+ - [Production Considerations](#production-considerations)
14
+ - [Troubleshooting](#troubleshooting)
15
+
16
+ ## Installation and Setup
17
+
18
+ ### 1. Install the Plugin
19
+
20
+ ```bash
21
+ npm install foreground-location
22
+ npx cap sync
23
+ ```
24
+
25
+ ### 2. Platform Configuration
26
+
27
+ #### Android Setup
28
+
29
+ **Add permissions to `android/app/src/main/AndroidManifest.xml`:**
30
+
31
+ ```xml
32
+ <!-- Location permissions -->
33
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
34
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
35
+
36
+ <!-- Foreground service permissions -->
37
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
38
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
39
+
40
+ <!-- Notification permission (Android 13+) -->
41
+ <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
42
+
43
+ <!-- Internet for API integration -->
44
+ <uses-permission android:name="android.permission.INTERNET" />
45
+ ```
46
+
47
+ **Optional: Add custom notification icon to `android/app/src/main/res/drawable/`:**
48
+
49
+ ```xml
50
+ <!-- ic_location_tracking.xml -->
51
+ <vector xmlns:android="http://schemas.android.com/apk/res/android"
52
+ android:width="24dp"
53
+ android:height="24dp"
54
+ android:viewportWidth="24"
55
+ android:viewportHeight="24"
56
+ android:tint="?attr/colorOnPrimary">
57
+ <path
58
+ android:fillColor="@android:color/white"
59
+ android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"/>
60
+ </vector>
61
+ ```
62
+
63
+ #### iOS Setup
64
+
65
+ **Add usage descriptions to `ios/App/App/Info.plist`:**
66
+
67
+ ```xml
68
+ <dict>
69
+ <!-- Other keys... -->
70
+
71
+ <!-- Location permissions -->
72
+ <key>NSLocationWhenInUseUsageDescription</key>
73
+ <string>This app needs location access to track your position while actively using the app</string>
74
+
75
+ <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
76
+ <string>This app needs continuous location access to provide location-based services</string>
77
+
78
+ <!-- Background modes for location tracking -->
79
+ <key>UIBackgroundModes</key>
80
+ <array>
81
+ <string>location</string>
82
+ </array>
83
+
84
+ <!-- Optional: Support for background app refresh -->
85
+ <key>UIBackgroundRefreshStatusAvailable</key>
86
+ <true/>
87
+ </dict>
88
+ ```
89
+
90
+ ### 3. Build and Sync
91
+
92
+ ```bash
93
+ # Build the project
94
+ npm run build
95
+
96
+ # Sync with native platforms
97
+ npx cap sync
98
+
99
+ # Open in native IDEs for testing
100
+ npx cap open ios
101
+ npx cap open android
102
+ ```
103
+
104
+ ## Permission Management
105
+
106
+ ### Basic Permission Handling
107
+
108
+ ```typescript
109
+ import { ForeGroundLocation, LocationPermissionStatus } from 'foreground-location';
110
+
111
+ class PermissionManager {
112
+ /**
113
+ * Check current permission status
114
+ */
115
+ async checkPermissions(): Promise<LocationPermissionStatus> {
116
+ try {
117
+ const permissions = await ForeGroundLocation.checkPermissions();
118
+ console.log('Current permissions:', {
119
+ location: permissions.location,
120
+ backgroundLocation: permissions.backgroundLocation,
121
+ notifications: permissions.notifications,
122
+ });
123
+ return permissions;
124
+ } catch (error) {
125
+ console.error('Failed to check permissions:', error);
126
+ throw error;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Request all required permissions
132
+ */
133
+ async requestPermissions(): Promise<boolean> {
134
+ try {
135
+ const permissions = await ForeGroundLocation.requestPermissions();
136
+
137
+ // Check if basic location permission is granted
138
+ if (permissions.location !== 'granted') {
139
+ throw new Error('Location permission is required for this feature');
140
+ }
141
+
142
+ // Log permission status
143
+ console.log('Permission results:', {
144
+ location: permissions.location,
145
+ backgroundLocation: permissions.backgroundLocation,
146
+ notifications: permissions.notifications,
147
+ });
148
+
149
+ return true;
150
+ } catch (error) {
151
+ console.error('Permission request failed:', error);
152
+ return false;
153
+ }
154
+ }
155
+
156
+ /**
157
+ * Handle permission states with user-friendly messages
158
+ */
159
+ async handlePermissions(): Promise<boolean> {
160
+ const permissions = await this.checkPermissions();
161
+
162
+ switch (permissions.location) {
163
+ case 'granted':
164
+ console.log('✅ Location permission granted');
165
+ return true;
166
+
167
+ case 'denied':
168
+ console.log('❌ Location permission denied permanently');
169
+ // Show instructions to enable in settings
170
+ this.showPermissionInstructions();
171
+ return false;
172
+
173
+ case 'prompt':
174
+ console.log('🔄 Requesting location permission...');
175
+ return await this.requestPermissions();
176
+
177
+ default:
178
+ console.log('❓ Unknown permission state');
179
+ return false;
180
+ }
181
+ }
182
+
183
+ private showPermissionInstructions(): void {
184
+ // Implement UI to guide user to app settings
185
+ alert('Please enable location permissions in your device settings to use this feature.');
186
+ }
187
+ }
188
+ ```
189
+
190
+ ## Basic Implementation
191
+
192
+ ### Simple Location Tracking
193
+
194
+ ```typescript
195
+ import { ForeGroundLocation, LocationResult, ServiceStatus } from 'foreground-location';
196
+
197
+ class BasicLocationService {
198
+ private permissionManager = new PermissionManager();
199
+ private locationListener: any = null;
200
+ private statusListener: any = null;
201
+
202
+ /**
203
+ * Start basic location tracking
204
+ */
205
+ async startTracking(): Promise<void> {
206
+ try {
207
+ // 1. Handle permissions
208
+ const hasPermissions = await this.permissionManager.handlePermissions();
209
+ if (!hasPermissions) {
210
+ throw new Error('Location permissions required');
211
+ }
212
+
213
+ // 2. Set up event listeners
214
+ await this.setupListeners();
215
+
216
+ // 3. Start the foreground service
217
+ await ForeGroundLocation.startForegroundLocationService({
218
+ interval: 30000, // Update every 30 seconds
219
+ fastestInterval: 15000, // But not faster than 15 seconds
220
+ priority: 'HIGH_ACCURACY',
221
+ notification: {
222
+ title: 'Location Tracking Active',
223
+ text: 'Tracking your location in the background',
224
+ icon: 'ic_location_tracking', // Optional custom icon
225
+ },
226
+ enableHighAccuracy: true,
227
+ distanceFilter: 5, // Only update if moved 5+ meters
228
+ });
229
+
230
+ console.log('✅ Location tracking started successfully');
231
+ } catch (error) {
232
+ console.error('❌ Failed to start location tracking:', error);
233
+ throw error;
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Set up event listeners for location and status updates
239
+ */
240
+ private async setupListeners(): Promise<void> {
241
+ // Listen for location updates
242
+ this.locationListener = await ForeGroundLocation.addListener(
243
+ 'locationUpdate',
244
+ this.handleLocationUpdate.bind(this),
245
+ );
246
+
247
+ // Listen for service status changes
248
+ this.statusListener = await ForeGroundLocation.addListener(
249
+ 'serviceStatusChanged',
250
+ this.handleStatusChange.bind(this),
251
+ );
252
+ }
253
+
254
+ /**
255
+ * Handle incoming location updates
256
+ */
257
+ private handleLocationUpdate(location: LocationResult): void {
258
+ console.log('📍 New location update:', {
259
+ coordinates: `${location.latitude}, ${location.longitude}`,
260
+ accuracy: `${location.accuracy}m`,
261
+ timestamp: location.timestamp,
262
+ speed: location.speed ? `${location.speed} m/s` : 'N/A',
263
+ altitude: location.altitude ? `${location.altitude}m` : 'N/A',
264
+ });
265
+
266
+ // Update your app's UI or store the location
267
+ this.updateLocationDisplay(location);
268
+ }
269
+
270
+ /**
271
+ * Handle service status changes
272
+ */
273
+ private handleStatusChange(status: ServiceStatus): void {
274
+ console.log('🔄 Service status changed:', status);
275
+
276
+ if (status.error) {
277
+ console.error('❌ Service error:', status.error);
278
+ this.handleServiceError(status.error);
279
+ }
280
+
281
+ if (!status.isRunning) {
282
+ console.log('⏹️ Location service stopped');
283
+ }
284
+ }
285
+
286
+ /**
287
+ * Handle service errors
288
+ */
289
+ private handleServiceError(error: string): void {
290
+ // Implement error handling based on your app's needs
291
+ switch (error) {
292
+ case 'LOCATION_SERVICES_DISABLED':
293
+ alert('Please enable location services in your device settings');
294
+ break;
295
+ case 'PERMISSION_DENIED':
296
+ alert('Location permission was revoked. Please re-enable it.');
297
+ break;
298
+ default:
299
+ console.error('Unknown service error:', error);
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Update your app's location display
305
+ */
306
+ private updateLocationDisplay(location: LocationResult): void {
307
+ // Implement based on your UI framework
308
+ // For example, update a map, show coordinates, etc.
309
+ }
310
+
311
+ /**
312
+ * Stop location tracking
313
+ */
314
+ async stopTracking(): Promise<void> {
315
+ try {
316
+ // Stop the location service
317
+ await ForeGroundLocation.stopForegroundLocationService();
318
+
319
+ // Remove event listeners
320
+ if (this.locationListener) {
321
+ this.locationListener.remove();
322
+ this.locationListener = null;
323
+ }
324
+
325
+ if (this.statusListener) {
326
+ this.statusListener.remove();
327
+ this.statusListener = null;
328
+ }
329
+
330
+ console.log('✅ Location tracking stopped successfully');
331
+ } catch (error) {
332
+ console.error('❌ Failed to stop location tracking:', error);
333
+ throw error;
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Get current service status
339
+ */
340
+ async getServiceStatus(): Promise<{ isRunning: boolean }> {
341
+ return await ForeGroundLocation.isServiceRunning();
342
+ }
343
+
344
+ /**
345
+ * Get a single location update without starting the service
346
+ */
347
+ async getCurrentLocation(): Promise<LocationResult> {
348
+ const hasPermissions = await this.permissionManager.handlePermissions();
349
+ if (!hasPermissions) {
350
+ throw new Error('Location permissions required');
351
+ }
352
+
353
+ return await ForeGroundLocation.getCurrentLocation();
354
+ }
355
+ }
356
+ ```
357
+
358
+ ## Advanced Features
359
+
360
+ ### Power Management and Dynamic Settings
361
+
362
+ ```typescript
363
+ class AdvancedLocationService extends BasicLocationService {
364
+ private currentMode: 'efficient' | 'accurate' | 'custom' = 'efficient';
365
+
366
+ /**
367
+ * Start with battery-efficient settings
368
+ */
369
+ async startEfficientMode(): Promise<void> {
370
+ await this.startTracking();
371
+
372
+ await ForeGroundLocation.updateLocationSettings({
373
+ interval: 120000, // 2 minutes
374
+ fastestInterval: 60000, // 1 minute minimum
375
+ priority: 'BALANCED_POWER',
376
+ enableHighAccuracy: false,
377
+ distanceFilter: 20, // 20 meters
378
+ notification: {
379
+ title: 'Efficient Tracking',
380
+ text: 'Battery-optimized location tracking',
381
+ },
382
+ });
383
+
384
+ this.currentMode = 'efficient';
385
+ console.log('🔋 Switched to efficient mode');
386
+ }
387
+
388
+ /**
389
+ * Switch to high accuracy mode
390
+ */
391
+ async switchToAccurateMode(): Promise<void> {
392
+ try {
393
+ await ForeGroundLocation.updateLocationSettings({
394
+ interval: 10000, // 10 seconds
395
+ fastestInterval: 5000, // 5 seconds
396
+ priority: 'HIGH_ACCURACY',
397
+ enableHighAccuracy: true,
398
+ distanceFilter: 1, // 1 meter
399
+ notification: {
400
+ title: 'High Accuracy Mode',
401
+ text: 'Precise location tracking active',
402
+ },
403
+ });
404
+
405
+ this.currentMode = 'accurate';
406
+ console.log('🎯 Switched to accurate mode');
407
+ } catch (error) {
408
+ console.error('Failed to switch to accurate mode:', error);
409
+ }
410
+ }
411
+
412
+ /**
413
+ * Automatically adjust settings based on speed
414
+ */
415
+ private handleLocationUpdate(location: LocationResult): void {
416
+ super.handleLocationUpdate(location);
417
+
418
+ // Auto-adjust based on movement speed
419
+ if (location.speed !== undefined) {
420
+ if (location.speed > 15 && this.currentMode !== 'accurate') {
421
+ // High speed detected, switch to accurate mode
422
+ this.switchToAccurateMode();
423
+ } else if (location.speed < 2 && this.currentMode !== 'efficient') {
424
+ // Stationary or slow movement, switch to efficient mode
425
+ this.startEfficientMode();
426
+ }
427
+ }
428
+ }
429
+
430
+ /**
431
+ * Get comprehensive service information
432
+ */
433
+ async getServiceInfo(): Promise<any> {
434
+ const [serviceStatus, apiStatus] = await Promise.all([
435
+ ForeGroundLocation.isServiceRunning(),
436
+ ForeGroundLocation.getApiServiceStatus(),
437
+ ]);
438
+
439
+ return {
440
+ service: serviceStatus,
441
+ api: apiStatus,
442
+ mode: this.currentMode,
443
+ timestamp: new Date().toISOString(),
444
+ };
445
+ }
446
+ }
447
+ ```
448
+
449
+ ## API Integration Examples
450
+
451
+ ### Basic API Integration
452
+
453
+ ```typescript
454
+ import { ForeGroundLocation, ApiServiceConfig } from 'foreground-location';
455
+
456
+ class ApiLocationService extends BasicLocationService {
457
+ private apiConfig: ApiServiceConfig;
458
+
459
+ constructor(apiEndpoint: string, authToken: string) {
460
+ super();
461
+ this.apiConfig = {
462
+ url: apiEndpoint,
463
+ type: 'POST',
464
+ header: {
465
+ Authorization: `Bearer ${authToken}`,
466
+ 'Content-Type': 'application/json',
467
+ 'X-Client': 'mobile-app',
468
+ },
469
+ apiInterval: 5, // Send data every 5 minutes
470
+ additionalParams: {
471
+ deviceId: this.getDeviceId(),
472
+ appVersion: '1.0.0',
473
+ },
474
+ };
475
+ }
476
+
477
+ /**
478
+ * Start tracking with API integration
479
+ */
480
+ async startApiTracking(): Promise<void> {
481
+ try {
482
+ const hasPermissions = await this.permissionManager.handlePermissions();
483
+ if (!hasPermissions) {
484
+ throw new Error('Location permissions required');
485
+ }
486
+
487
+ await this.setupListeners();
488
+
489
+ // Start with API configuration
490
+ await ForeGroundLocation.startForegroundLocationService({
491
+ interval: 30000,
492
+ fastestInterval: 15000,
493
+ priority: 'HIGH_ACCURACY',
494
+ notification: {
495
+ title: 'Location Sync Active',
496
+ text: 'Syncing location data to server',
497
+ },
498
+ api: this.apiConfig,
499
+ });
500
+
501
+ // Monitor API service
502
+ this.startApiMonitoring();
503
+
504
+ console.log('✅ API location tracking started');
505
+ } catch (error) {
506
+ console.error('❌ Failed to start API tracking:', error);
507
+ throw error;
508
+ }
509
+ }
510
+
511
+ /**
512
+ * Monitor API service health
513
+ */
514
+ private startApiMonitoring(): void {
515
+ setInterval(async () => {
516
+ try {
517
+ const status = await ForeGroundLocation.getApiServiceStatus();
518
+
519
+ console.log('📊 API Status:', {
520
+ enabled: status.isEnabled,
521
+ buffer: status.bufferSize,
522
+ healthy: status.isHealthy,
523
+ });
524
+
525
+ // Handle unhealthy API service
526
+ if (!status.isHealthy) {
527
+ console.warn('⚠️ API service unhealthy, attempting reset...');
528
+ await ForeGroundLocation.resetApiCircuitBreaker();
529
+ }
530
+
531
+ // Handle buffer overflow
532
+ if (status.bufferSize > 100) {
533
+ console.warn('⚠️ API buffer overflow, clearing old data...');
534
+ await ForeGroundLocation.clearApiBuffers();
535
+ }
536
+ } catch (error) {
537
+ console.error('Failed to monitor API status:', error);
538
+ }
539
+ }, 60000); // Check every minute
540
+ }
541
+
542
+ /**
543
+ * Update API configuration
544
+ */
545
+ async updateApiConfig(newConfig: Partial<ApiServiceConfig>): Promise<void> {
546
+ this.apiConfig = { ...this.apiConfig, ...newConfig };
547
+
548
+ // Restart service with new config
549
+ await ForeGroundLocation.updateLocationSettings({
550
+ api: this.apiConfig,
551
+ });
552
+ }
553
+
554
+ private getDeviceId(): string {
555
+ // Implement device ID generation
556
+ return 'device-' + Math.random().toString(36).substr(2, 9);
557
+ }
558
+ }
559
+ ```
560
+
561
+ ### Advanced API Integration with Auth Refresh
562
+
563
+ ```typescript
564
+ class SecureApiLocationService extends ApiLocationService {
565
+ private authToken: string = '';
566
+ private refreshToken: string = '';
567
+ private tokenExpiryTime: number = 0;
568
+
569
+ constructor(apiEndpoint: string, initialAuthToken: string, refreshToken: string) {
570
+ super(apiEndpoint, initialAuthToken);
571
+ this.authToken = initialAuthToken;
572
+ this.refreshToken = refreshToken;
573
+ this.scheduleTokenRefresh();
574
+ }
575
+
576
+ /**
577
+ * Schedule automatic token refresh
578
+ */
579
+ private scheduleTokenRefresh(): void {
580
+ setInterval(async () => {
581
+ if (Date.now() >= this.tokenExpiryTime - 300000) {
582
+ // 5 minutes before expiry
583
+ await this.refreshAuthToken();
584
+ }
585
+ }, 60000); // Check every minute
586
+ }
587
+
588
+ /**
589
+ * Refresh authentication token
590
+ */
591
+ private async refreshAuthToken(): Promise<void> {
592
+ try {
593
+ const response = await fetch('https://api.yourservice.com/auth/refresh', {
594
+ method: 'POST',
595
+ headers: {
596
+ 'Content-Type': 'application/json',
597
+ Authorization: `Bearer ${this.refreshToken}`,
598
+ },
599
+ });
600
+
601
+ if (response.ok) {
602
+ const data = await response.json();
603
+ this.authToken = data.accessToken;
604
+ this.tokenExpiryTime = Date.now() + data.expiresIn * 1000;
605
+
606
+ // Update API configuration with new token
607
+ await this.updateApiConfig({
608
+ header: {
609
+ ...this.apiConfig.header,
610
+ Authorization: `Bearer ${this.authToken}`,
611
+ },
612
+ });
613
+
614
+ console.log('🔐 Auth token refreshed successfully');
615
+ } else {
616
+ throw new Error('Token refresh failed');
617
+ }
618
+ } catch (error) {
619
+ console.error('❌ Failed to refresh auth token:', error);
620
+ // Handle auth failure (logout user, show login screen, etc.)
621
+ }
622
+ }
623
+
624
+ /**
625
+ * Handle API service errors with retry logic
626
+ */
627
+ protected handleServiceError(error: string): void {
628
+ super.handleServiceError(error);
629
+
630
+ if (error.includes('401') || error.includes('403')) {
631
+ // Authentication error, attempt token refresh
632
+ this.refreshAuthToken();
633
+ }
634
+ }
635
+ }
636
+ ```
637
+
638
+ ## Framework-Specific Examples
639
+
640
+ ### React/Ionic Implementation
641
+
642
+ ```typescript
643
+ import React, { useState, useEffect, useCallback } from 'react';
644
+ import {
645
+ IonButton,
646
+ IonContent,
647
+ IonHeader,
648
+ IonPage,
649
+ IonTitle,
650
+ IonToolbar,
651
+ IonCard,
652
+ IonCardContent,
653
+ IonCardHeader,
654
+ IonCardTitle,
655
+ IonItem,
656
+ IonLabel,
657
+ IonIcon,
658
+ IonBadge
659
+ } from '@ionic/react';
660
+ import { locationOutline, playOutline, stopOutline } from 'ionicons/icons';
661
+ import { ForeGroundLocation, LocationResult, ApiServiceStatus } from 'foreground-location';
662
+
663
+ const LocationTracker: React.FC = () => {
664
+ const [isTracking, setIsTracking] = useState(false);
665
+ const [currentLocation, setCurrentLocation] = useState<LocationResult | null>(null);
666
+ const [apiStatus, setApiStatus] = useState<ApiServiceStatus | null>(null);
667
+ const [error, setError] = useState<string | null>(null);
668
+
669
+ // Custom hook for location tracking
670
+ const useLocationTracking = () => {
671
+ const startTracking = useCallback(async () => {
672
+ try {
673
+ setError(null);
674
+
675
+ // Check permissions
676
+ const permissions = await ForeGroundLocation.checkPermissions();
677
+ if (permissions.location !== 'granted') {
678
+ const requested = await ForeGroundLocation.requestPermissions();
679
+ if (requested.location !== 'granted') {
680
+ throw new Error('Location permission denied');
681
+ }
682
+ }
683
+
684
+ // Add listeners
685
+ await ForeGroundLocation.addListener('locationUpdate', (location: LocationResult) => {
686
+ setCurrentLocation(location);
687
+ console.log('📍 Location update:', location);
688
+ });
689
+
690
+ await ForeGroundLocation.addListener('serviceStatusChanged', (status) => {
691
+ setIsTracking(status.isRunning);
692
+ if (status.error) {
693
+ setError(status.error);
694
+ }
695
+ });
696
+
697
+ // Start service
698
+ await ForeGroundLocation.startForegroundLocationService({
699
+ interval: 10000,
700
+ fastestInterval: 5000,
701
+ priority: 'HIGH_ACCURACY',
702
+ notification: {
703
+ title: 'Location Tracking',
704
+ text: 'Tracking your location'
705
+ },
706
+ api: {
707
+ url: 'https://api.example.com/locations',
708
+ type: 'POST',
709
+ header: {
710
+ 'Authorization': 'Bearer your-token',
711
+ 'Content-Type': 'application/json'
712
+ },
713
+ apiInterval: 2
714
+ }
715
+ });
716
+
717
+ setIsTracking(true);
718
+ } catch (err) {
719
+ setError(err instanceof Error ? err.message : 'Unknown error');
720
+ setIsTracking(false);
721
+ }
722
+ }, []);
723
+
724
+ const stopTracking = useCallback(async () => {
725
+ try {
726
+ await ForeGroundLocation.stopForegroundLocationService();
727
+ await ForeGroundLocation.removeAllListeners();
728
+ setIsTracking(false);
729
+ setCurrentLocation(null);
730
+ setApiStatus(null);
731
+ } catch (err) {
732
+ console.error('Failed to stop tracking:', err);
733
+ }
734
+ }, []);
735
+
736
+ return { startTracking, stopTracking };
737
+ };
738
+
739
+ const { startTracking, stopTracking } = useLocationTracking();
740
+
741
+ // Monitor API status
742
+ useEffect(() => {
743
+ if (!isTracking) return;
744
+
745
+ const checkApiStatus = async () => {
746
+ try {
747
+ const status = await ForeGroundLocation.getApiServiceStatus();
748
+ setApiStatus(status);
749
+ } catch (error) {
750
+ console.error('Failed to check API status:', error);
751
+ }
752
+ };
753
+
754
+ const interval = setInterval(checkApiStatus, 30000);
755
+ checkApiStatus(); // Initial check
756
+
757
+ return () => clearInterval(interval);
758
+ }, [isTracking]);
759
+
760
+ // Cleanup on unmount
761
+ useEffect(() => {
762
+ return () => {
763
+ if (isTracking) {
764
+ stopTracking();
765
+ }
766
+ };
767
+ }, [isTracking, stopTracking]);
768
+
769
+ return (
770
+ <IonPage>
771
+ <IonHeader>
772
+ <IonToolbar>
773
+ <IonTitle>Location Tracker</IonTitle>
774
+ </IonToolbar>
775
+ </IonHeader>
776
+
777
+ <IonContent className="ion-padding">
778
+ {/* Control Buttons */}
779
+ <IonCard>
780
+ <IonCardHeader>
781
+ <IonCardTitle>
782
+ <IonIcon icon={locationOutline} /> Location Service
783
+ </IonCardTitle>
784
+ </IonCardHeader>
785
+ <IonCardContent>
786
+ <IonButton
787
+ expand="block"
788
+ color={isTracking ? "danger" : "primary"}
789
+ onClick={isTracking ? stopTracking : startTracking}
790
+ >
791
+ <IonIcon icon={isTracking ? stopOutline : playOutline} slot="start" />
792
+ {isTracking ? 'Stop Tracking' : 'Start Tracking'}
793
+ </IonButton>
794
+
795
+ {error && (
796
+ <div style={{ color: 'var(--ion-color-danger)', marginTop: '10px' }}>
797
+ Error: {error}
798
+ </div>
799
+ )}
800
+ </IonCardContent>
801
+ </IonCard>
802
+
803
+ {/* Current Location */}
804
+ {currentLocation && (
805
+ <IonCard>
806
+ <IonCardHeader>
807
+ <IonCardTitle>Current Location</IonCardTitle>
808
+ </IonCardHeader>
809
+ <IonCardContent>
810
+ <IonItem>
811
+ <IonLabel>
812
+ <h3>Coordinates</h3>
813
+ <p>{currentLocation.latitude.toFixed(6)}, {currentLocation.longitude.toFixed(6)}</p>
814
+ </IonLabel>
815
+ </IonItem>
816
+ <IonItem>
817
+ <IonLabel>
818
+ <h3>Accuracy</h3>
819
+ <p>{currentLocation.accuracy.toFixed(1)} meters</p>
820
+ </IonLabel>
821
+ </IonItem>
822
+ {currentLocation.speed !== undefined && (
823
+ <IonItem>
824
+ <IonLabel>
825
+ <h3>Speed</h3>
826
+ <p>{(currentLocation.speed * 3.6).toFixed(1)} km/h</p>
827
+ </IonLabel>
828
+ </IonItem>
829
+ )}
830
+ <IonItem>
831
+ <IonLabel>
832
+ <h3>Last Update</h3>
833
+ <p>{new Date(currentLocation.timestamp).toLocaleString()}</p>
834
+ </IonLabel>
835
+ </IonItem>
836
+ </IonCardContent>
837
+ </IonCard>
838
+ )}
839
+
840
+ {/* API Status */}
841
+ {apiStatus && (
842
+ <IonCard>
843
+ <IonCardHeader>
844
+ <IonCardTitle>API Service Status</IonCardTitle>
845
+ </IonCardHeader>
846
+ <IonCardContent>
847
+ <IonItem>
848
+ <IonLabel>Service Status</IonLabel>
849
+ <IonBadge color={apiStatus.isEnabled ? "success" : "medium"}>
850
+ {apiStatus.isEnabled ? "Enabled" : "Disabled"}
851
+ </IonBadge>
852
+ </IonItem>
853
+ <IonItem>
854
+ <IonLabel>Health Status</IonLabel>
855
+ <IonBadge color={apiStatus.isHealthy ? "success" : "warning"}>
856
+ {apiStatus.isHealthy ? "Healthy" : "Unhealthy"}
857
+ </IonBadge>
858
+ </IonItem>
859
+ <IonItem>
860
+ <IonLabel>Buffer Size</IonLabel>
861
+ <IonBadge color={apiStatus.bufferSize > 50 ? "warning" : "primary"}>
862
+ {apiStatus.bufferSize}
863
+ </IonBadge>
864
+ </IonItem>
865
+ </IonCardContent>
866
+ </IonCard>
867
+ )}
868
+ </IonContent>
869
+ </IonPage>
870
+ );
871
+ };
872
+
873
+ export default LocationTracker;
874
+ ```
875
+
876
+ ### Angular Service Implementation
877
+
878
+ ```typescript
879
+ import { Injectable, OnDestroy } from '@angular/core';
880
+ import { BehaviorSubject, Observable, interval, Subscription } from 'rxjs';
881
+ import {
882
+ ForeGroundLocation,
883
+ LocationResult,
884
+ ServiceStatus,
885
+ ApiServiceStatus,
886
+ LocationServiceOptions,
887
+ } from 'foreground-location';
888
+
889
+ @Injectable({
890
+ providedIn: 'root',
891
+ })
892
+ export class LocationTrackingService implements OnDestroy {
893
+ private locationSubject = new BehaviorSubject<LocationResult | null>(null);
894
+ private statusSubject = new BehaviorSubject<ServiceStatus>({ isRunning: false });
895
+ private apiStatusSubject = new BehaviorSubject<ApiServiceStatus | null>(null);
896
+
897
+ private locationListener: any = null;
898
+ private statusListener: any = null;
899
+ private apiMonitorSubscription: Subscription | null = null;
900
+
901
+ // Public observables
902
+ public location$: Observable<LocationResult | null> = this.locationSubject.asObservable();
903
+ public status$: Observable<ServiceStatus> = this.statusSubject.asObservable();
904
+ public apiStatus$: Observable<ApiServiceStatus | null> = this.apiStatusSubject.asObservable();
905
+
906
+ /**
907
+ * Start location tracking with configuration
908
+ */
909
+ async startTracking(options: LocationServiceOptions): Promise<void> {
910
+ try {
911
+ // Request permissions
912
+ const permissions = await ForeGroundLocation.requestPermissions();
913
+ if (permissions.location !== 'granted') {
914
+ throw new Error('Location permission required');
915
+ }
916
+
917
+ // Setup listeners
918
+ await this.setupListeners();
919
+
920
+ // Start the service
921
+ await ForeGroundLocation.startForegroundLocationService(options);
922
+
923
+ // Start API monitoring if API is configured
924
+ if (options.api) {
925
+ this.startApiMonitoring();
926
+ }
927
+
928
+ console.log('✅ Location tracking started');
929
+ } catch (error) {
930
+ console.error('❌ Failed to start location tracking:', error);
931
+ throw error;
932
+ }
933
+ }
934
+
935
+ /**
936
+ * Stop location tracking
937
+ */
938
+ async stopTracking(): Promise<void> {
939
+ try {
940
+ await ForeGroundLocation.stopForegroundLocationService();
941
+ await this.cleanup();
942
+ console.log('✅ Location tracking stopped');
943
+ } catch (error) {
944
+ console.error('❌ Failed to stop location tracking:', error);
945
+ throw error;
946
+ }
947
+ }
948
+
949
+ /**
950
+ * Get current location once
951
+ */
952
+ async getCurrentLocation(): Promise<LocationResult> {
953
+ const permissions = await ForeGroundLocation.checkPermissions();
954
+ if (permissions.location !== 'granted') {
955
+ throw new Error('Location permission required');
956
+ }
957
+ return await ForeGroundLocation.getCurrentLocation();
958
+ }
959
+
960
+ /**
961
+ * Update location service settings
962
+ */
963
+ async updateSettings(options: LocationServiceOptions): Promise<void> {
964
+ await ForeGroundLocation.updateLocationSettings(options);
965
+ }
966
+
967
+ /**
968
+ * Clear API buffers
969
+ */
970
+ async clearApiBuffers(): Promise<void> {
971
+ await ForeGroundLocation.clearApiBuffers();
972
+ }
973
+
974
+ /**
975
+ * Reset API circuit breaker
976
+ */
977
+ async resetApiCircuitBreaker(): Promise<void> {
978
+ await ForeGroundLocation.resetApiCircuitBreaker();
979
+ }
980
+
981
+ /**
982
+ * Setup event listeners
983
+ */
984
+ private async setupListeners(): Promise<void> {
985
+ this.locationListener = await ForeGroundLocation.addListener('locationUpdate', (location: LocationResult) => {
986
+ this.locationSubject.next(location);
987
+ });
988
+
989
+ this.statusListener = await ForeGroundLocation.addListener('serviceStatusChanged', (status: ServiceStatus) => {
990
+ this.statusSubject.next(status);
991
+ });
992
+ }
993
+
994
+ /**
995
+ * Start monitoring API service status
996
+ */
997
+ private startApiMonitoring(): void {
998
+ this.apiMonitorSubscription = interval(30000).subscribe(async () => {
999
+ try {
1000
+ const status = await ForeGroundLocation.getApiServiceStatus();
1001
+ this.apiStatusSubject.next(status);
1002
+ } catch (error) {
1003
+ console.error('Failed to check API status:', error);
1004
+ }
1005
+ });
1006
+ }
1007
+
1008
+ /**
1009
+ * Cleanup listeners and subscriptions
1010
+ */
1011
+ private async cleanup(): Promise<void> {
1012
+ if (this.locationListener) {
1013
+ this.locationListener.remove();
1014
+ this.locationListener = null;
1015
+ }
1016
+
1017
+ if (this.statusListener) {
1018
+ this.statusListener.remove();
1019
+ this.statusListener = null;
1020
+ }
1021
+
1022
+ if (this.apiMonitorSubscription) {
1023
+ this.apiMonitorSubscription.unsubscribe();
1024
+ this.apiMonitorSubscription = null;
1025
+ }
1026
+
1027
+ await ForeGroundLocation.removeAllListeners();
1028
+
1029
+ // Reset subjects
1030
+ this.statusSubject.next({ isRunning: false });
1031
+ this.apiStatusSubject.next(null);
1032
+ }
1033
+
1034
+ /**
1035
+ * OnDestroy lifecycle hook
1036
+ */
1037
+ ngOnDestroy(): void {
1038
+ this.cleanup();
1039
+ }
1040
+ }
1041
+ ```
1042
+
1043
+ ### Vue.js Composition API
1044
+
1045
+ ```typescript
1046
+ import { ref, onMounted, onUnmounted, computed } from 'vue';
1047
+ import {
1048
+ ForeGroundLocation,
1049
+ LocationResult,
1050
+ ServiceStatus,
1051
+ ApiServiceStatus,
1052
+ LocationServiceOptions,
1053
+ } from 'foreground-location';
1054
+
1055
+ export function useLocationTracking() {
1056
+ const isTracking = ref(false);
1057
+ const currentLocation = ref<LocationResult | null>(null);
1058
+ const serviceStatus = ref<ServiceStatus>({ isRunning: false });
1059
+ const apiStatus = ref<ApiServiceStatus | null>(null);
1060
+ const error = ref<string | null>(null);
1061
+
1062
+ let locationListener: any = null;
1063
+ let statusListener: any = null;
1064
+ let apiMonitorInterval: number | null = null;
1065
+
1066
+ // Computed properties
1067
+ const locationDisplay = computed(() => {
1068
+ if (!currentLocation.value) return null;
1069
+
1070
+ return {
1071
+ coordinates: `${currentLocation.value.latitude.toFixed(6)}, ${currentLocation.value.longitude.toFixed(6)}`,
1072
+ accuracy: `${currentLocation.value.accuracy.toFixed(1)}m`,
1073
+ speed: currentLocation.value.speed ? `${(currentLocation.value.speed * 3.6).toFixed(1)} km/h` : 'N/A',
1074
+ timestamp: new Date(currentLocation.value.timestamp).toLocaleString(),
1075
+ };
1076
+ });
1077
+
1078
+ const apiStatusDisplay = computed(() => {
1079
+ if (!apiStatus.value) return null;
1080
+
1081
+ return {
1082
+ status: apiStatus.value.isEnabled ? 'Enabled' : 'Disabled',
1083
+ health: apiStatus.value.isHealthy ? 'Healthy' : 'Unhealthy',
1084
+ bufferWarning: apiStatus.value.bufferSize > 50,
1085
+ };
1086
+ });
1087
+
1088
+ /**
1089
+ * Start location tracking
1090
+ */
1091
+ const startTracking = async (options: LocationServiceOptions) => {
1092
+ try {
1093
+ error.value = null;
1094
+
1095
+ // Check permissions
1096
+ const permissions = await ForeGroundLocation.checkPermissions();
1097
+ if (permissions.location !== 'granted') {
1098
+ const requested = await ForeGroundLocation.requestPermissions();
1099
+ if (requested.location !== 'granted') {
1100
+ throw new Error('Location permission denied');
1101
+ }
1102
+ }
1103
+
1104
+ // Setup listeners
1105
+ locationListener = await ForeGroundLocation.addListener('locationUpdate', (location: LocationResult) => {
1106
+ currentLocation.value = location;
1107
+ });
1108
+
1109
+ statusListener = await ForeGroundLocation.addListener('serviceStatusChanged', (status: ServiceStatus) => {
1110
+ serviceStatus.value = status;
1111
+ isTracking.value = status.isRunning;
1112
+ if (status.error) {
1113
+ error.value = status.error;
1114
+ }
1115
+ });
1116
+
1117
+ // Start service
1118
+ await ForeGroundLocation.startForegroundLocationService(options);
1119
+
1120
+ // Monitor API if configured
1121
+ if (options.api) {
1122
+ startApiMonitoring();
1123
+ }
1124
+
1125
+ isTracking.value = true;
1126
+ } catch (err) {
1127
+ error.value = err instanceof Error ? err.message : 'Unknown error';
1128
+ isTracking.value = false;
1129
+ }
1130
+ };
1131
+
1132
+ /**
1133
+ * Stop location tracking
1134
+ */
1135
+ const stopTracking = async () => {
1136
+ try {
1137
+ await ForeGroundLocation.stopForegroundLocationService();
1138
+ await cleanup();
1139
+ isTracking.value = false;
1140
+ } catch (err) {
1141
+ console.error('Failed to stop tracking:', err);
1142
+ }
1143
+ };
1144
+
1145
+ /**
1146
+ * Start API monitoring
1147
+ */
1148
+ const startApiMonitoring = () => {
1149
+ apiMonitorInterval = window.setInterval(async () => {
1150
+ try {
1151
+ const status = await ForeGroundLocation.getApiServiceStatus();
1152
+ apiStatus.value = status;
1153
+ } catch (error) {
1154
+ console.error('Failed to check API status:', error);
1155
+ }
1156
+ }, 30000);
1157
+ };
1158
+
1159
+ /**
1160
+ * Cleanup resources
1161
+ */
1162
+ const cleanup = async () => {
1163
+ if (locationListener) {
1164
+ locationListener.remove();
1165
+ locationListener = null;
1166
+ }
1167
+
1168
+ if (statusListener) {
1169
+ statusListener.remove();
1170
+ statusListener = null;
1171
+ }
1172
+
1173
+ if (apiMonitorInterval) {
1174
+ clearInterval(apiMonitorInterval);
1175
+ apiMonitorInterval = null;
1176
+ }
1177
+
1178
+ await ForeGroundLocation.removeAllListeners();
1179
+
1180
+ currentLocation.value = null;
1181
+ serviceStatus.value = { isRunning: false };
1182
+ apiStatus.value = null;
1183
+ error.value = null;
1184
+ };
1185
+
1186
+ // Lifecycle hooks
1187
+ onMounted(() => {
1188
+ // Component mounted
1189
+ });
1190
+
1191
+ onUnmounted(() => {
1192
+ cleanup();
1193
+ });
1194
+
1195
+ return {
1196
+ // State
1197
+ isTracking,
1198
+ currentLocation,
1199
+ serviceStatus,
1200
+ apiStatus,
1201
+ error,
1202
+
1203
+ // Computed
1204
+ locationDisplay,
1205
+ apiStatusDisplay,
1206
+
1207
+ // Methods
1208
+ startTracking,
1209
+ stopTracking,
1210
+ cleanup,
1211
+ };
1212
+ }
1213
+ ```
1214
+
1215
+ ## Production Considerations
1216
+
1217
+ ### Performance Optimization
1218
+
1219
+ ```typescript
1220
+ class ProductionLocationService extends BasicLocationService {
1221
+ private performanceMetrics = {
1222
+ locationUpdates: 0,
1223
+ apiCalls: 0,
1224
+ errors: 0,
1225
+ startTime: Date.now(),
1226
+ };
1227
+
1228
+ /**
1229
+ * Production-ready configuration
1230
+ */
1231
+ async startProductionTracking(): Promise<void> {
1232
+ const config: LocationServiceOptions = {
1233
+ // Balanced settings for production
1234
+ interval: 60000, // 1 minute intervals
1235
+ fastestInterval: 30000, // Minimum 30 seconds
1236
+ priority: 'BALANCED_POWER', // Balance accuracy and battery
1237
+ distanceFilter: 10, // 10 meters minimum movement
1238
+ enableHighAccuracy: false, // Disable GPS for battery
1239
+
1240
+ notification: {
1241
+ title: 'Location Services',
1242
+ text: 'App is tracking your location',
1243
+ icon: 'location_on',
1244
+ },
1245
+
1246
+ api: {
1247
+ url: process.env.API_ENDPOINT!,
1248
+ type: 'POST',
1249
+ header: {
1250
+ Authorization: `Bearer ${await this.getValidToken()}`,
1251
+ 'Content-Type': 'application/json',
1252
+ 'X-App-Version': process.env.APP_VERSION || '1.0.0',
1253
+ 'X-Platform': this.getPlatform(),
1254
+ },
1255
+ apiInterval: 10, // Send every 10 minutes
1256
+ additionalParams: {
1257
+ userId: await this.getUserId(),
1258
+ deviceId: await this.getDeviceId(),
1259
+ sessionId: this.generateSessionId(),
1260
+ },
1261
+ },
1262
+ };
1263
+
1264
+ await this.startTracking();
1265
+ await ForeGroundLocation.updateLocationSettings(config);
1266
+
1267
+ this.startPerformanceMonitoring();
1268
+ }
1269
+
1270
+ /**
1271
+ * Monitor performance metrics
1272
+ */
1273
+ private startPerformanceMonitoring(): void {
1274
+ setInterval(() => {
1275
+ const uptime = Date.now() - this.performanceMetrics.startTime;
1276
+ const avgUpdatesPerHour = (this.performanceMetrics.locationUpdates / uptime) * 3600000;
1277
+
1278
+ console.log('📊 Performance Metrics:', {
1279
+ uptime: `${Math.round(uptime / 60000)} minutes`,
1280
+ locationUpdates: this.performanceMetrics.locationUpdates,
1281
+ apiCalls: this.performanceMetrics.apiCalls,
1282
+ errors: this.performanceMetrics.errors,
1283
+ avgUpdatesPerHour: Math.round(avgUpdatesPerHour),
1284
+ });
1285
+
1286
+ // Send metrics to analytics service
1287
+ this.sendAnalytics('location_service_performance', this.performanceMetrics);
1288
+ }, 600000); // Every 10 minutes
1289
+ }
1290
+
1291
+ protected handleLocationUpdate(location: LocationResult): void {
1292
+ super.handleLocationUpdate(location);
1293
+ this.performanceMetrics.locationUpdates++;
1294
+
1295
+ // Validate location data
1296
+ if (this.isValidLocation(location)) {
1297
+ this.processValidLocation(location);
1298
+ } else {
1299
+ console.warn('⚠️ Invalid location data received:', location);
1300
+ this.performanceMetrics.errors++;
1301
+ }
1302
+ }
1303
+
1304
+ private isValidLocation(location: LocationResult): boolean {
1305
+ return (
1306
+ location.latitude >= -90 &&
1307
+ location.latitude <= 90 &&
1308
+ location.longitude >= -180 &&
1309
+ location.longitude <= 180 &&
1310
+ location.accuracy > 0 &&
1311
+ location.accuracy < 1000
1312
+ );
1313
+ }
1314
+
1315
+ private async getValidToken(): Promise<string> {
1316
+ // Implement token validation and refresh logic
1317
+ return 'valid-token';
1318
+ }
1319
+
1320
+ private getPlatform(): string {
1321
+ // Detect platform
1322
+ return 'unknown';
1323
+ }
1324
+
1325
+ private async getUserId(): Promise<string> {
1326
+ // Get user ID from your auth system
1327
+ return 'user-id';
1328
+ }
1329
+
1330
+ private async getDeviceId(): Promise<string> {
1331
+ // Generate or retrieve persistent device ID
1332
+ return 'device-id';
1333
+ }
1334
+
1335
+ private generateSessionId(): string {
1336
+ return 'session-' + Math.random().toString(36).substr(2, 9);
1337
+ }
1338
+
1339
+ private sendAnalytics(event: string, data: any): void {
1340
+ // Send to your analytics service
1341
+ }
1342
+
1343
+ private processValidLocation(location: LocationResult): void {
1344
+ // Process valid location data
1345
+ }
1346
+ }
1347
+ ```
1348
+
1349
+ ### Error Handling and Recovery
1350
+
1351
+ ```typescript
1352
+ class RobustLocationService extends ProductionLocationService {
1353
+ private retryCount = 0;
1354
+ private maxRetries = 3;
1355
+ private backoffDelay = 1000;
1356
+
1357
+ /**
1358
+ * Start with automatic retry on failure
1359
+ */
1360
+ async startWithRetry(): Promise<void> {
1361
+ while (this.retryCount < this.maxRetries) {
1362
+ try {
1363
+ await this.startProductionTracking();
1364
+ this.retryCount = 0; // Reset on success
1365
+ return;
1366
+ } catch (error) {
1367
+ this.retryCount++;
1368
+ console.error(`❌ Start attempt ${this.retryCount} failed:`, error);
1369
+
1370
+ if (this.retryCount >= this.maxRetries) {
1371
+ throw new Error(`Failed to start after ${this.maxRetries} attempts: ${error}`);
1372
+ }
1373
+
1374
+ // Exponential backoff
1375
+ const delay = this.backoffDelay * Math.pow(2, this.retryCount - 1);
1376
+ console.log(`⏳ Retrying in ${delay}ms...`);
1377
+ await this.sleep(delay);
1378
+ }
1379
+ }
1380
+ }
1381
+
1382
+ /**
1383
+ * Handle service errors with recovery
1384
+ */
1385
+ protected handleServiceError(error: string): void {
1386
+ super.handleServiceError(error);
1387
+
1388
+ // Implement specific recovery strategies
1389
+ switch (error) {
1390
+ case 'LOCATION_SERVICES_DISABLED':
1391
+ this.handleLocationServicesDisabled();
1392
+ break;
1393
+ case 'PERMISSION_DENIED':
1394
+ this.handlePermissionDenied();
1395
+ break;
1396
+ default:
1397
+ this.handleGenericError(error);
1398
+ }
1399
+ }
1400
+
1401
+ private async handleLocationServicesDisabled(): Promise<void> {
1402
+ console.log('🔧 Attempting to handle disabled location services...');
1403
+
1404
+ // Wait and retry
1405
+ await this.sleep(5000);
1406
+
1407
+ try {
1408
+ const permissions = await ForeGroundLocation.checkPermissions();
1409
+ if (permissions.location === 'granted') {
1410
+ console.log('🔄 Attempting to restart service...');
1411
+ await this.startWithRetry();
1412
+ }
1413
+ } catch (error) {
1414
+ console.error('Failed to recover from disabled location services:', error);
1415
+ }
1416
+ }
1417
+
1418
+ private async handlePermissionDenied(): Promise<void> {
1419
+ console.log('🔧 Handling permission denied...');
1420
+
1421
+ // Show user guidance
1422
+ this.showPermissionGuidance();
1423
+
1424
+ // Set up permission monitoring
1425
+ this.monitorPermissionChanges();
1426
+ }
1427
+
1428
+ private handleGenericError(error: string): void {
1429
+ console.log('🔧 Handling generic error:', error);
1430
+
1431
+ // Schedule retry
1432
+ setTimeout(() => {
1433
+ this.startWithRetry();
1434
+ }, 30000); // Retry after 30 seconds
1435
+ }
1436
+
1437
+ private showPermissionGuidance(): void {
1438
+ // Show user-friendly permission guidance
1439
+ alert('Please enable location permissions in your device settings to continue tracking.');
1440
+ }
1441
+
1442
+ private monitorPermissionChanges(): void {
1443
+ const checkPermissions = async () => {
1444
+ try {
1445
+ const permissions = await ForeGroundLocation.checkPermissions();
1446
+ if (permissions.location === 'granted') {
1447
+ console.log('✅ Permissions restored, restarting service...');
1448
+ await this.startWithRetry();
1449
+ clearInterval(permissionCheck);
1450
+ }
1451
+ } catch (error) {
1452
+ console.error('Permission monitoring error:', error);
1453
+ }
1454
+ };
1455
+
1456
+ const permissionCheck = setInterval(checkPermissions, 10000); // Check every 10 seconds
1457
+
1458
+ // Stop monitoring after 5 minutes
1459
+ setTimeout(() => {
1460
+ clearInterval(permissionCheck);
1461
+ }, 300000);
1462
+ }
1463
+
1464
+ private sleep(ms: number): Promise<void> {
1465
+ return new Promise((resolve) => setTimeout(resolve, ms));
1466
+ }
1467
+ }
1468
+ ```
1469
+
1470
+ ## Troubleshooting
1471
+
1472
+ ### Common Issues and Solutions
1473
+
1474
+ | Issue | Symptoms | Cause | Solution |
1475
+ | -------------------- | ---------------------------------------- | ----------------------------- | ------------------------------------------------------------ |
1476
+ | Service won't start | Error on startForegroundLocationService | Missing notification config | Ensure notification.title and notification.text are provided |
1477
+ | No location updates | Service running but no location events | Permission issues | Check permissions with checkPermissions() |
1478
+ | High battery drain | Device heating up, battery draining fast | Too frequent updates | Increase interval, use BALANCED_POWER priority |
1479
+ | API data not sending | Buffer size increasing, no API calls | Network/authentication issues | Check API endpoint, verify auth token |
1480
+ | Location inaccurate | Large accuracy values | Wrong settings | Use HIGH_ACCURACY priority, enable GPS |
1481
+ | App crashes on start | App closes when starting service | Native permission issues | Ensure all required permissions in manifest |
1482
+
1483
+ ### Debug Utilities
1484
+
1485
+ ```typescript
1486
+ class LocationDebugger {
1487
+ /**
1488
+ * Comprehensive system check
1489
+ */
1490
+ static async runSystemCheck(): Promise<void> {
1491
+ console.log('🔍 Running location system diagnostics...');
1492
+
1493
+ try {
1494
+ // Check permissions
1495
+ const permissions = await ForeGroundLocation.checkPermissions();
1496
+ console.log('📋 Permissions:', permissions);
1497
+
1498
+ // Check service status
1499
+ const serviceStatus = await ForeGroundLocation.isServiceRunning();
1500
+ console.log('⚙️ Service Status:', serviceStatus);
1501
+
1502
+ // Try getting current location
1503
+ try {
1504
+ const location = await ForeGroundLocation.getCurrentLocation();
1505
+ console.log('📍 Current Location:', location);
1506
+ } catch (error) {
1507
+ console.log('❌ Current Location Error:', error);
1508
+ }
1509
+
1510
+ // Check API status
1511
+ try {
1512
+ const apiStatus = await ForeGroundLocation.getApiServiceStatus();
1513
+ console.log('🌐 API Status:', apiStatus);
1514
+ } catch (error) {
1515
+ console.log('❌ API Status Error:', error);
1516
+ }
1517
+
1518
+ console.log('✅ System check completed');
1519
+ } catch (error) {
1520
+ console.error('❌ System check failed:', error);
1521
+ }
1522
+ }
1523
+
1524
+ /**
1525
+ * Monitor location service health
1526
+ */
1527
+ static startHealthMonitoring(): void {
1528
+ setInterval(async () => {
1529
+ try {
1530
+ const timestamp = new Date().toISOString();
1531
+ const serviceStatus = await ForeGroundLocation.isServiceRunning();
1532
+ const apiStatus = await ForeGroundLocation.getApiServiceStatus();
1533
+
1534
+ console.log(`🏥 Health Check [${timestamp}]:`, {
1535
+ service: serviceStatus.isRunning ? '✅' : '❌',
1536
+ api: apiStatus.isEnabled ? '✅' : '❌',
1537
+ healthy: apiStatus.isHealthy ? '✅' : '⚠️',
1538
+ buffer: apiStatus.bufferSize,
1539
+ });
1540
+
1541
+ // Alert on issues
1542
+ if (!serviceStatus.isRunning) {
1543
+ console.warn('⚠️ Location service is not running!');
1544
+ }
1545
+
1546
+ if (apiStatus.isEnabled && !apiStatus.isHealthy) {
1547
+ console.warn('⚠️ API service is unhealthy!');
1548
+ }
1549
+
1550
+ if (apiStatus.bufferSize > 100) {
1551
+ console.warn('⚠️ API buffer is getting full:', apiStatus.bufferSize);
1552
+ }
1553
+ } catch (error) {
1554
+ console.error('❌ Health monitoring error:', error);
1555
+ }
1556
+ }, 60000); // Every minute
1557
+ }
1558
+ }
1559
+
1560
+ // Usage
1561
+ LocationDebugger.runSystemCheck();
1562
+ LocationDebugger.startHealthMonitoring();
1563
+ ```
1564
+
1565
+ ### Testing Utilities
1566
+
1567
+ ```typescript
1568
+ class LocationTester {
1569
+ /**
1570
+ * Test location service lifecycle
1571
+ */
1572
+ static async testLifecycle(): Promise<void> {
1573
+ console.log('🧪 Testing location service lifecycle...');
1574
+
1575
+ try {
1576
+ // Test permissions
1577
+ console.log('1. Testing permissions...');
1578
+ const permissions = await ForeGroundLocation.checkPermissions();
1579
+ if (permissions.location !== 'granted') {
1580
+ const requested = await ForeGroundLocation.requestPermissions();
1581
+ console.log('Permission result:', requested);
1582
+ }
1583
+
1584
+ // Test service start
1585
+ console.log('2. Testing service start...');
1586
+ await ForeGroundLocation.startForegroundLocationService({
1587
+ interval: 5000,
1588
+ notification: {
1589
+ title: 'Test Location Service',
1590
+ text: 'Testing location tracking',
1591
+ },
1592
+ });
1593
+
1594
+ // Wait for location updates
1595
+ console.log('3. Waiting for location updates...');
1596
+ await new Promise((resolve) => {
1597
+ let updateCount = 0;
1598
+ ForeGroundLocation.addListener('locationUpdate', (location) => {
1599
+ updateCount++;
1600
+ console.log(`Location update ${updateCount}:`, location);
1601
+
1602
+ if (updateCount >= 3) {
1603
+ resolve(undefined);
1604
+ }
1605
+ });
1606
+ });
1607
+
1608
+ // Test service stop
1609
+ console.log('4. Testing service stop...');
1610
+ await ForeGroundLocation.stopForegroundLocationService();
1611
+ await ForeGroundLocation.removeAllListeners();
1612
+
1613
+ console.log('✅ Lifecycle test completed successfully');
1614
+ } catch (error) {
1615
+ console.error('❌ Lifecycle test failed:', error);
1616
+ }
1617
+ }
1618
+
1619
+ /**
1620
+ * Test API integration
1621
+ */
1622
+ static async testApiIntegration(apiUrl: string): Promise<void> {
1623
+ console.log('🧪 Testing API integration...');
1624
+
1625
+ try {
1626
+ await ForeGroundLocation.startForegroundLocationService({
1627
+ interval: 10000,
1628
+ notification: {
1629
+ title: 'API Test',
1630
+ text: 'Testing API integration',
1631
+ },
1632
+ api: {
1633
+ url: apiUrl,
1634
+ type: 'POST',
1635
+ header: {
1636
+ 'Content-Type': 'application/json',
1637
+ },
1638
+ apiInterval: 1, // Send every minute for testing
1639
+ },
1640
+ });
1641
+
1642
+ // Monitor API status
1643
+ const checkInterval = setInterval(async () => {
1644
+ const status = await ForeGroundLocation.getApiServiceStatus();
1645
+ console.log('API Status:', status);
1646
+ }, 10000);
1647
+
1648
+ // Run for 2 minutes
1649
+ setTimeout(async () => {
1650
+ clearInterval(checkInterval);
1651
+ await ForeGroundLocation.stopForegroundLocationService();
1652
+ console.log('✅ API test completed');
1653
+ }, 120000);
1654
+ } catch (error) {
1655
+ console.error('❌ API test failed:', error);
1656
+ }
1657
+ }
1658
+ }
1659
+ ```
1660
+
1661
+ This comprehensive setup and examples guide provides everything you need to implement the Capacitor Foreground Location plugin correctly in your application. Remember to always test thoroughly on real devices and handle edge cases appropriately for production use.
1662
+
1663
+ useEffect(() => {
1664
+ return () => {
1665
+ // Cleanup on unmount
1666
+ if (locationListener) {
1667
+ locationListener.remove();
1668
+ }
1669
+ if (isTracking) {
1670
+ ForeGroundLocation.stopLocationTracking();
1671
+ }
1672
+ };
1673
+ }, [locationListener, isTracking]);
1674
+
1675
+ const startTracking = async () => {
1676
+ try {
1677
+ // Setup location listener
1678
+ const listener = await ForeGroundLocation.addListener('locationUpdate', (location) => {
1679
+ setCurrentLocation(location);
1680
+ console.log('Location update received:', location);
1681
+ });
1682
+ setLocationListener(listener);
1683
+
1684
+ // Configure API service
1685
+ const apiConfig: ApiServiceConfig = {
1686
+ baseUrl: 'https://your-api.com',
1687
+ endpoint: '/api/locations',
1688
+ method: 'POST',
1689
+ headers: {
1690
+ 'Authorization': 'Bearer your-token',
1691
+ 'Content-Type': 'application/json'
1692
+ },
1693
+ batchSize: 10,
1694
+ retryAttempts: 3,
1695
+ retryDelay: 1000,
1696
+ timeout: 30000,
1697
+ circuitBreakerThreshold: 5,
1698
+ bufferSize: 100
1699
+ };
1700
+
1701
+ // Start tracking
1702
+ await ForeGroundLocation.startLocationTracking({
1703
+ interval: 10000,
1704
+ fastestInterval: 5000,
1705
+ priority: 'HIGH_ACCURACY',
1706
+ apiService: apiConfig
1707
+ });
1708
+
1709
+ setIsTracking(true);
1710
+
1711
+ // Start monitoring API status
1712
+ monitorApiStatus();
1713
+
1714
+ } catch (error) {
1715
+ console.error('Failed to start tracking:', error);
1716
+ }
1717
+
1718
+ };
1719
+
1720
+ const stopTracking = async () => {
1721
+ try {
1722
+ await ForeGroundLocation.stopLocationTracking();
1723
+
1724
+ if (locationListener) {
1725
+ locationListener.remove();
1726
+ setLocationListener(null);
1727
+ }
1728
+
1729
+ setIsTracking(false);
1730
+ setApiStatus(null);
1731
+
1732
+ } catch (error) {
1733
+ console.error('Failed to stop tracking:', error);
1734
+ }
1735
+
1736
+ };
1737
+
1738
+ const monitorApiStatus = () => {
1739
+ const checkStatus = async () => {
1740
+ try {
1741
+ const status = await ForeGroundLocation.getApiServiceStatus();
1742
+ setApiStatus(status);
1743
+ } catch (error) {
1744
+ console.error('Failed to get API status:', error);
1745
+ }
1746
+ };
1747
+
1748
+ // Check immediately and then every 30 seconds
1749
+ checkStatus();
1750
+ const interval = setInterval(checkStatus, 30000);
1751
+
1752
+ // Cleanup interval when tracking stops
1753
+ setTimeout(() => {
1754
+ if (!isTracking) {
1755
+ clearInterval(interval);
1756
+ }
1757
+ }, 100);
1758
+
1759
+ };
1760
+
1761
+ const clearBuffers = async () => {
1762
+ try {
1763
+ await ForeGroundLocation.clearApiBuffers();
1764
+ console.log('Buffers cleared');
1765
+ } catch (error) {
1766
+ console.error('Failed to clear buffers:', error);
1767
+ }
1768
+ };
1769
+
1770
+ const resetCircuitBreaker = async () => {
1771
+ try {
1772
+ await ForeGroundLocation.resetApiCircuitBreaker();
1773
+ console.log('Circuit breaker reset');
1774
+ } catch (error) {
1775
+ console.error('Failed to reset circuit breaker:', error);
1776
+ }
1777
+ };
1778
+
1779
+ return (
1780
+ <IonPage>
1781
+ <IonHeader>
1782
+ <IonToolbar>
1783
+ <IonTitle>Location Tracker</IonTitle>
1784
+ </IonToolbar>
1785
+ </IonHeader>
1786
+ <IonContent>
1787
+ <IonItem>
1788
+ <IonLabel>
1789
+ <h2>Tracking Status</h2>
1790
+ <p>{isTracking ? 'Active' : 'Inactive'}</p>
1791
+ </IonLabel>
1792
+ </IonItem>
1793
+
1794
+ {currentLocation && (
1795
+ <IonItem>
1796
+ <IonLabel>
1797
+ <h2>Current Location</h2>
1798
+ <p>Lat: {currentLocation.latitude.toFixed(6)}</p>
1799
+ <p>Lng: {currentLocation.longitude.toFixed(6)}</p>
1800
+ <p>Accuracy: {currentLocation.accuracy}m</p>
1801
+ <p>Time: {new Date(currentLocation.timestamp).toLocaleString()}</p>
1802
+ </IonLabel>
1803
+ </IonItem>
1804
+ )}
1805
+
1806
+ {apiStatus && (
1807
+ <IonItem>
1808
+ <IonLabel>
1809
+ <h2>API Service Status</h2>
1810
+ <p>Active: {apiStatus.isActive ? 'Yes' : 'No'}</p>
1811
+ <p>Buffered: {apiStatus.bufferedCount} locations</p>
1812
+ <p>Circuit Breaker: {apiStatus.circuitBreakerOpen ? 'Open' : 'Closed'}</p>
1813
+ {apiStatus.lastSuccessfulCall && (
1814
+ <p>Last Success: {new Date(apiStatus.lastSuccessfulCall).toLocaleString()}</p>
1815
+ )}
1816
+ {apiStatus.lastError && (
1817
+ <p>Last Error: {apiStatus.lastError}</p>
1818
+ )}
1819
+ </IonLabel>
1820
+ </IonItem>
1821
+ )}
1822
+
1823
+ <IonButton
1824
+ expand="block"
1825
+ onClick={isTracking ? stopTracking : startTracking}
1826
+ color={isTracking ? 'danger' : 'primary'}
1827
+ >
1828
+ {isTracking ? 'Stop Tracking' : 'Start Tracking'}
1829
+ </IonButton>
1830
+
1831
+ {apiStatus && (
1832
+ <>
1833
+ <IonButton expand="block" fill="outline" onClick={clearBuffers}>
1834
+ Clear API Buffers
1835
+ </IonButton>
1836
+
1837
+ {apiStatus.circuitBreakerOpen && (
1838
+ <IonButton expand="block" fill="outline" onClick={resetCircuitBreaker}>
1839
+ Reset Circuit Breaker
1840
+ </IonButton>
1841
+ )}
1842
+ </>
1843
+ )}
1844
+ </IonContent>
1845
+ </IonPage>
1846
+
1847
+ );
1848
+ };
1849
+
1850
+ export default LocationTracker;
1851
+ ```
1852
+
1853
+ ## Error Handling
1854
+
1855
+ ### Comprehensive Error Handling Example
1856
+
1857
+ ```typescript
1858
+ import { ForeGroundLocation } from '@xconcepts/foreground-location';
1859
+
1860
+ class RobustLocationService {
1861
+ private maxRetries = 3;
1862
+ private retryCount = 0;
1863
+
1864
+ async startTrackingWithErrorHandling() {
1865
+ try {
1866
+ await this.attemptStartTracking();
1867
+ } catch (error) {
1868
+ await this.handleStartError(error);
1869
+ }
1870
+ }
1871
+
1872
+ private async attemptStartTracking() {
1873
+ try {
1874
+ await ForeGroundLocation.startLocationTracking({
1875
+ interval: 10000,
1876
+ fastestInterval: 5000,
1877
+ priority: 'HIGH_ACCURACY',
1878
+ apiService: {
1879
+ baseUrl: 'https://api.example.com',
1880
+ endpoint: '/locations',
1881
+ method: 'POST',
1882
+ headers: { Authorization: 'Bearer token' },
1883
+ batchSize: 10,
1884
+ retryAttempts: 3,
1885
+ timeout: 30000,
1886
+ },
1887
+ });
1888
+
1889
+ this.retryCount = 0; // Reset on success
1890
+ } catch (error) {
1891
+ throw error;
1892
+ }
1893
+ }
1894
+
1895
+ private async handleStartError(error: any) {
1896
+ console.error('Location tracking error:', error);
1897
+
1898
+ if (this.retryCount < this.maxRetries) {
1899
+ this.retryCount++;
1900
+ console.log(`Retrying... Attempt ${this.retryCount}/${this.maxRetries}`);
1901
+
1902
+ // Wait before retry
1903
+ await new Promise((resolve) => setTimeout(resolve, 2000 * this.retryCount));
1904
+
1905
+ try {
1906
+ await this.attemptStartTracking();
1907
+ } catch (retryError) {
1908
+ await this.handleStartError(retryError);
1909
+ }
1910
+ } else {
1911
+ // Max retries reached
1912
+ console.error('Max retries reached. Location tracking failed.');
1913
+ this.handleFinalError(error);
1914
+ }
1915
+ }
1916
+
1917
+ private handleFinalError(error: any) {
1918
+ // Handle different error types
1919
+ if (error.message?.includes('permission')) {
1920
+ console.error('Permission denied. Please grant location permissions.');
1921
+ // Show permission request dialog
1922
+ } else if (error.message?.includes('GPS')) {
1923
+ console.error('GPS is disabled. Please enable location services.');
1924
+ // Show GPS enable prompt
1925
+ } else if (error.message?.includes('network')) {
1926
+ console.error('Network error. API service may not be available.');
1927
+ // Try without API service
1928
+ this.startWithoutApi();
1929
+ } else {
1930
+ console.error('Unknown error occurred:', error);
1931
+ // Show generic error message
1932
+ }
1933
+ }
1934
+
1935
+ private async startWithoutApi() {
1936
+ try {
1937
+ console.log('Starting location tracking without API service...');
1938
+ await ForeGroundLocation.startLocationTracking({
1939
+ interval: 10000,
1940
+ fastestInterval: 5000,
1941
+ priority: 'HIGH_ACCURACY',
1942
+ // No apiService configuration
1943
+ });
1944
+ console.log('Location tracking started without API service');
1945
+ } catch (error) {
1946
+ console.error('Failed to start even without API service:', error);
1947
+ }
1948
+ }
1949
+ }
1950
+ ```
1951
+
1952
+ ## Best Practices
1953
+
1954
+ ### Performance Optimization
1955
+
1956
+ 1. **Choose appropriate intervals**:
1957
+ - For real-time tracking: 5-10 seconds
1958
+ - For periodic updates: 30-60 seconds
1959
+ - For battery saving: 2-5 minutes
1960
+
1961
+ 2. **Use suitable priority levels**:
1962
+ - `HIGH_ACCURACY`: For navigation apps
1963
+ - `BALANCED_POWER_ACCURACY`: For most apps
1964
+ - `LOW_POWER`: For background tracking
1965
+ - `NO_POWER`: For passive location updates
1966
+
1967
+ 3. **Configure API batching**:
1968
+ - Small batches (5-10): For real-time requirements
1969
+ - Large batches (20-50): For efficient network usage
1970
+
1971
+ ### Memory Management
1972
+
1973
+ ```typescript
1974
+ // Monitor and manage buffer sizes
1975
+ const monitorMemoryUsage = async () => {
1976
+ const status = await ForeGroundLocation.getApiServiceStatus();
1977
+
1978
+ if (status.bufferedCount > 80) {
1979
+ // 80% of default buffer size
1980
+ console.warn('Buffer getting full, consider clearing or increasing batch frequency');
1981
+
1982
+ // Option 1: Clear buffers
1983
+ await ForeGroundLocation.clearApiBuffers();
1984
+
1985
+ // Option 2: Adjust configuration (restart with smaller buffer)
1986
+ // await restartWithSmallerBuffer();
1987
+ }
1988
+ };
1989
+ ```
1990
+
1991
+ ### Security Considerations
1992
+
1993
+ ```typescript
1994
+ // Secure API configuration
1995
+ const getSecureApiConfig = async (): Promise<ApiServiceConfig> => {
1996
+ const token = await getSecureToken(); // From secure storage
1997
+
1998
+ return {
1999
+ baseUrl: await getApiEndpoint(), // From secure config
2000
+ endpoint: '/locations',
2001
+ method: 'POST',
2002
+ headers: {
2003
+ Authorization: `Bearer ${token}`,
2004
+ 'Content-Type': 'application/json',
2005
+ 'X-Client-Version': getAppVersion(),
2006
+ 'X-Request-ID': generateRequestId(),
2007
+ },
2008
+ batchSize: 10,
2009
+ retryAttempts: 3,
2010
+ timeout: 30000,
2011
+ };
2012
+ };
2013
+
2014
+ // Rotate tokens periodically
2015
+ const rotateAuthToken = async () => {
2016
+ try {
2017
+ const newToken = await refreshAuthToken();
2018
+
2019
+ // Stop current tracking
2020
+ await ForeGroundLocation.stopLocationTracking();
2021
+
2022
+ // Restart with new token
2023
+ const newConfig = await getSecureApiConfig();
2024
+ await ForeGroundLocation.startLocationTracking({
2025
+ interval: 10000,
2026
+ fastestInterval: 5000,
2027
+ priority: 'HIGH_ACCURACY',
2028
+ apiService: newConfig,
2029
+ });
2030
+ } catch (error) {
2031
+ console.error('Failed to rotate auth token:', error);
2032
+ }
2033
+ };
2034
+ ```
2035
+
2036
+ ### Testing and Debugging
2037
+
2038
+ ```typescript
2039
+ // Debug mode configuration
2040
+ const DEBUG_MODE = process.env.NODE_ENV === 'development';
2041
+
2042
+ const getDebugApiConfig = (): ApiServiceConfig => ({
2043
+ baseUrl: DEBUG_MODE ? 'https://api-dev.example.com' : 'https://api.example.com',
2044
+ endpoint: '/locations',
2045
+ method: 'POST',
2046
+ headers: {
2047
+ Authorization: `Bearer ${getToken()}`,
2048
+ 'Content-Type': 'application/json',
2049
+ ...(DEBUG_MODE && { 'X-Debug-Mode': 'true' }),
2050
+ },
2051
+ batchSize: DEBUG_MODE ? 3 : 10, // Smaller batches in debug
2052
+ retryAttempts: DEBUG_MODE ? 1 : 3,
2053
+ timeout: DEBUG_MODE ? 10000 : 30000,
2054
+ });
2055
+
2056
+ // Enhanced logging for debugging
2057
+ const debugLocationUpdate = (location: any) => {
2058
+ if (DEBUG_MODE) {
2059
+ console.log('Location Debug Info:', {
2060
+ coordinates: `${location.latitude}, ${location.longitude}`,
2061
+ accuracy: `${location.accuracy}m`,
2062
+ timestamp: new Date(location.timestamp).toISOString(),
2063
+ speed: location.speed ? `${location.speed} m/s` : 'N/A',
2064
+ bearing: location.bearing ? `${location.bearing}°` : 'N/A',
2065
+ });
2066
+ }
2067
+ };
2068
+ ```
2069
+
2070
+ This completes the comprehensive setup and examples guide for the Capacitor Foreground Location plugin with API service integration.
2071
+
2072
+ ### 3. iOS Configuration
2073
+
2074
+ #### Update Info.plist
2075
+
2076
+ ```xml
2077
+ <!-- ios/App/App/Info.plist -->
2078
+ <key>NSLocationWhenInUseUsageDescription</key>
2079
+ <string>This app needs location access to track your route.</string>
2080
+
2081
+ <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
2082
+ <string>This app needs location access to track your route in the background.</string>
2083
+
2084
+ <!-- If using background location -->
2085
+ <key>UIBackgroundModes</key>
2086
+ <array>
2087
+ <string>location</string>
2088
+ </array>
2089
+ ```
2090
+
2091
+ ## Basic Usage Examples
2092
+
2093
+ ### Example 1: Simple Location Tracking
2094
+
2095
+ ```typescript
2096
+ import { ForeGroundLocation } from 'foreground-location';
2097
+ import type { LocationResult } from 'foreground-location';
2098
+
2099
+ export class LocationService {
2100
+ private locationListener: any;
2101
+
2102
+ async startTracking() {
2103
+ try {
2104
+ // Check and request permissions
2105
+ const permissions = await ForeGroundLocation.checkPermissions();
2106
+
2107
+ if (permissions.location !== 'granted') {
2108
+ const requestResult = await ForeGroundLocation.requestPermissions();
2109
+ if (requestResult.location !== 'granted') {
2110
+ throw new Error('Location permission denied');
2111
+ }
2112
+ }
2113
+
2114
+ // Start location service
2115
+ await ForeGroundLocation.startForegroundLocationService({
2116
+ notification: {
2117
+ title: 'Location Tracking',
2118
+ text: 'Tracking your location in the background',
2119
+ icon: 'ic_location',
2120
+ },
2121
+ interval: 30000, // 30 seconds
2122
+ fastestInterval: 15000, // 15 seconds
2123
+ priority: 'HIGH_ACCURACY',
2124
+ });
2125
+
2126
+ // Listen for location updates
2127
+ this.locationListener = await ForeGroundLocation.addListener('locationUpdate', (location: LocationResult) => {
2128
+ console.log('New location:', {
2129
+ lat: location.latitude,
2130
+ lng: location.longitude,
2131
+ accuracy: location.accuracy,
2132
+ time: location.timestamp,
2133
+ });
2134
+
2135
+ // Process location data
2136
+ this.handleLocationUpdate(location);
2137
+ });
2138
+
2139
+ console.log('Location tracking started successfully');
2140
+ } catch (error) {
2141
+ console.error('Failed to start location tracking:', error);
2142
+ throw error;
2143
+ }
2144
+ }
2145
+
2146
+ async stopTracking() {
2147
+ try {
2148
+ await ForeGroundLocation.stopForegroundLocationService();
2149
+
2150
+ if (this.locationListener) {
2151
+ this.locationListener.remove();
2152
+ this.locationListener = null;
2153
+ }
2154
+
2155
+ console.log('Location tracking stopped');
2156
+ } catch (error) {
2157
+ console.error('Failed to stop location tracking:', error);
2158
+ }
2159
+ }
2160
+
2161
+ private handleLocationUpdate(location: LocationResult) {
2162
+ // Store location data locally
2163
+ // Update UI
2164
+ // Send to analytics, etc.
2165
+ }
2166
+ }
2167
+ ```
2168
+
2169
+ ### Example 2: Distance-Based Tracking
2170
+
2171
+ ```typescript
2172
+ export class DistanceBasedTracking {
2173
+ async startDistanceTracking() {
2174
+ await ForeGroundLocation.startForegroundLocationService({
2175
+ notification: {
2176
+ title: 'Distance Tracking',
2177
+ text: 'Recording significant movement',
2178
+ },
2179
+ interval: 60000, // 1 minute baseline
2180
+ fastestInterval: 30000, // 30 seconds minimum
2181
+ priority: 'BALANCED_POWER', // Save battery
2182
+ distanceFilter: 50, // Only update every 50 meters
2183
+ });
2184
+
2185
+ await ForeGroundLocation.addListener('locationUpdate', (location) => {
2186
+ console.log(`Moved at least 50m: ${location.latitude}, ${location.longitude}`);
2187
+ });
2188
+ }
2189
+ }
2190
+ ```
2191
+
2192
+ ### Example 3: Battery-Optimized Tracking
2193
+
2194
+ ```typescript
2195
+ export class BatteryOptimizedTracking {
2196
+ async startLowPowerTracking() {
2197
+ await ForeGroundLocation.startForegroundLocationService({
2198
+ notification: {
2199
+ title: 'Low Power Tracking',
2200
+ text: 'Conserving battery while tracking',
2201
+ },
2202
+ interval: 300000, // 5 minutes
2203
+ fastestInterval: 180000, // 3 minutes
2204
+ priority: 'LOW_POWER', // Network-based location
2205
+ distanceFilter: 100, // Only significant movement
2206
+ });
2207
+ }
2208
+ }
2209
+ ```
2210
+
2211
+ ## API Service Integration
2212
+
2213
+ ### Example 4: Basic API Integration
2214
+
2215
+ ```typescript
2216
+ export class APILocationService {
2217
+ async startWithAPI() {
2218
+ await ForeGroundLocation.startForegroundLocationService({
2219
+ notification: {
2220
+ title: 'Route Recording',
2221
+ text: 'Uploading your journey to the cloud',
2222
+ },
2223
+ interval: 30000,
2224
+ priority: 'HIGH_ACCURACY',
2225
+
2226
+ // API service configuration
2227
+ api: {
2228
+ url: 'https://api.yourcompany.com/locations',
2229
+ type: 'POST',
2230
+ header: {
2231
+ 'Content-Type': 'application/json',
2232
+ Authorization: 'Bearer YOUR_API_TOKEN',
2233
+ 'X-Device-ID': await this.getDeviceId(),
2234
+ },
2235
+ additionalParams: {
2236
+ userId: await this.getCurrentUserId(),
2237
+ sessionId: this.generateSessionId(),
2238
+ appVersion: '1.0.0',
2239
+ },
2240
+ apiInterval: 5, // Send data every 5 minutes
2241
+ },
2242
+ });
2243
+
2244
+ // Monitor API service
2245
+ setInterval(async () => {
2246
+ const status = await ForeGroundLocation.getApiServiceStatus();
2247
+ console.log('API Status:', {
2248
+ enabled: status.isEnabled,
2249
+ bufferSize: status.bufferSize,
2250
+ healthy: status.isHealthy,
2251
+ });
2252
+
2253
+ if (!status.isHealthy) {
2254
+ console.warn('API service is unhealthy - check network connection');
2255
+ }
2256
+ }, 60000); // Check every minute
2257
+ }
2258
+
2259
+ private async getDeviceId(): Promise<string> {
2260
+ // Implementation to get unique device ID
2261
+ return 'device-123';
2262
+ }
2263
+
2264
+ private async getCurrentUserId(): Promise<string> {
2265
+ // Implementation to get current user ID
2266
+ return 'user-456';
2267
+ }
2268
+
2269
+ private generateSessionId(): string {
2270
+ return `session-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
2271
+ }
2272
+ }
2273
+ ```
2274
+
2275
+ ### Example 5: Advanced API Configuration with Authentication
2276
+
2277
+ ```typescript
2278
+ export class AuthenticatedAPIService {
2279
+ private authToken: string = '';
2280
+
2281
+ async startWithAuthenticatedAPI() {
2282
+ // Get fresh auth token
2283
+ this.authToken = await this.refreshAuthToken();
2284
+
2285
+ await ForeGroundLocation.startForegroundLocationService({
2286
+ notification: {
2287
+ title: 'Secure Tracking',
2288
+ text: 'Securely uploading location data',
2289
+ },
2290
+ interval: 20000,
2291
+ api: {
2292
+ url: 'https://secure-api.yourcompany.com/v1/locations',
2293
+ type: 'POST',
2294
+ header: {
2295
+ 'Content-Type': 'application/json',
2296
+ Authorization: `Bearer ${this.authToken}`,
2297
+ 'X-API-Version': '1.0',
2298
+ 'X-Client-Platform': 'mobile-app',
2299
+ },
2300
+ additionalParams: {
2301
+ userId: await this.getCurrentUserId(),
2302
+ deviceInfo: await this.getDeviceInfo(),
2303
+ trackingMode: 'high-accuracy',
2304
+ timestamp: new Date().toISOString(),
2305
+ },
2306
+ apiInterval: 3, // Send every 3 minutes for real-time tracking
2307
+ },
2308
+ });
2309
+
2310
+ // Set up token refresh
2311
+ this.setupTokenRefresh();
2312
+ }
2313
+
2314
+ private async refreshAuthToken(): Promise<string> {
2315
+ // Your authentication logic
2316
+ const response = await fetch('/api/auth/refresh', {
2317
+ method: 'POST',
2318
+ headers: { 'Content-Type': 'application/json' },
2319
+ body: JSON.stringify({ refreshToken: this.getStoredRefreshToken() }),
2320
+ });
2321
+
2322
+ const data = await response.json();
2323
+ return data.accessToken;
2324
+ }
2325
+
2326
+ private setupTokenRefresh() {
2327
+ // Refresh token every 50 minutes (assuming 1-hour expiry)
2328
+ setInterval(
2329
+ async () => {
2330
+ try {
2331
+ this.authToken = await this.refreshAuthToken();
2332
+ console.log('Auth token refreshed successfully');
2333
+
2334
+ // Update the running service with new token (restart with new config)
2335
+ await this.restartWithNewToken();
2336
+ } catch (error) {
2337
+ console.error('Failed to refresh auth token:', error);
2338
+ // Handle auth failure - maybe stop tracking or show user notification
2339
+ }
2340
+ },
2341
+ 50 * 60 * 1000,
2342
+ );
2343
+ }
2344
+
2345
+ private async restartWithNewToken() {
2346
+ // Restart service with new authentication token
2347
+ await ForeGroundLocation.stopForegroundLocationService();
2348
+ await this.startWithAuthenticatedAPI();
2349
+ }
2350
+ }
2351
+ ```
2352
+
2353
+ ### Example 6: API Error Handling and Recovery
2354
+
2355
+ ```typescript
2356
+ export class ResilientAPIService {
2357
+ async startResilientTracking() {
2358
+ await ForeGroundLocation.startForegroundLocationService({
2359
+ notification: {
2360
+ title: 'Smart Tracking',
2361
+ text: 'Intelligent location sync with failover',
2362
+ },
2363
+ interval: 15000,
2364
+ api: {
2365
+ url: 'https://primary-api.yourcompany.com/locations',
2366
+ type: 'POST',
2367
+ header: {
2368
+ 'Content-Type': 'application/json',
2369
+ Authorization: 'Bearer YOUR_TOKEN',
2370
+ },
2371
+ apiInterval: 2, // Frequent sync
2372
+ },
2373
+ });
2374
+
2375
+ // Monitor and handle API issues
2376
+ this.startAPIMonitoring();
2377
+ }
2378
+
2379
+ private startAPIMonitoring() {
2380
+ setInterval(async () => {
2381
+ const status = await ForeGroundLocation.getApiServiceStatus();
2382
+
2383
+ if (!status.isHealthy) {
2384
+ console.warn('API service is unhealthy');
2385
+
2386
+ // Check if buffer is getting too large
2387
+ if (status.bufferSize > 100) {
2388
+ console.warn('Large buffer detected, may need intervention');
2389
+
2390
+ // Option 1: Clear buffers to prevent memory issues
2391
+ // await ForeGroundLocation.clearApiBuffers();
2392
+
2393
+ // Option 2: Reset circuit breaker to retry immediately
2394
+ await ForeGroundLocation.resetApiCircuitBreaker();
2395
+
2396
+ // Option 3: Switch to backup API endpoint
2397
+ await this.switchToBackupAPI();
2398
+ }
2399
+ } else if (status.bufferSize === 0) {
2400
+ console.log('API service healthy, all data synced');
2401
+ }
2402
+ }, 30000); // Check every 30 seconds
2403
+ }
2404
+
2405
+ private async switchToBackupAPI() {
2406
+ console.log('Switching to backup API endpoint');
2407
+
2408
+ await ForeGroundLocation.stopForegroundLocationService();
2409
+
2410
+ await ForeGroundLocation.startForegroundLocationService({
2411
+ notification: {
2412
+ title: 'Backup Sync',
2413
+ text: 'Using backup server for location sync',
2414
+ },
2415
+ interval: 15000,
2416
+ api: {
2417
+ url: 'https://backup-api.yourcompany.com/locations',
2418
+ type: 'POST',
2419
+ header: {
2420
+ 'Content-Type': 'application/json',
2421
+ Authorization: 'Bearer YOUR_TOKEN',
2422
+ },
2423
+ apiInterval: 5, // Less frequent on backup
2424
+ },
2425
+ });
2426
+ }
2427
+ }
2428
+ ```
2429
+
2430
+ ## Advanced Configuration
2431
+
2432
+ ### Example 7: Dynamic Configuration Updates
2433
+
2434
+ ```typescript
2435
+ export class DynamicLocationService {
2436
+ private currentMode: 'normal' | 'high-accuracy' | 'battery-saver' = 'normal';
2437
+
2438
+ async startDynamicTracking() {
2439
+ await this.updateConfigurationFor('normal');
2440
+
2441
+ // Set up dynamic configuration based on app state
2442
+ document.addEventListener('visibilitychange', () => {
2443
+ if (document.hidden) {
2444
+ this.switchMode('battery-saver');
2445
+ } else {
2446
+ this.switchMode('high-accuracy');
2447
+ }
2448
+ });
2449
+ }
2450
+
2451
+ async switchMode(mode: 'normal' | 'high-accuracy' | 'battery-saver') {
2452
+ if (this.currentMode === mode) return;
2453
+
2454
+ console.log(`Switching to ${mode} mode`);
2455
+ this.currentMode = mode;
2456
+
2457
+ await this.updateConfigurationFor(mode);
2458
+ }
2459
+
2460
+ private async updateConfigurationFor(mode: string) {
2461
+ const configs = {
2462
+ 'high-accuracy': {
2463
+ notification: {
2464
+ title: 'High Accuracy Mode',
2465
+ text: 'Precise location tracking active',
2466
+ },
2467
+ interval: 5000,
2468
+ fastestInterval: 2000,
2469
+ priority: 'HIGH_ACCURACY' as const,
2470
+ distanceFilter: 5,
2471
+ api: { apiInterval: 1 },
2472
+ },
2473
+ normal: {
2474
+ notification: {
2475
+ title: 'Standard Tracking',
2476
+ text: 'Normal location tracking',
2477
+ },
2478
+ interval: 30000,
2479
+ fastestInterval: 15000,
2480
+ priority: 'BALANCED_POWER' as const,
2481
+ distanceFilter: 20,
2482
+ api: { apiInterval: 5 },
2483
+ },
2484
+ 'battery-saver': {
2485
+ notification: {
2486
+ title: 'Battery Saver Mode',
2487
+ text: 'Low power location tracking',
2488
+ },
2489
+ interval: 300000,
2490
+ fastestInterval: 180000,
2491
+ priority: 'LOW_POWER' as const,
2492
+ distanceFilter: 100,
2493
+ api: { apiInterval: 15 },
2494
+ },
2495
+ };
2496
+
2497
+ const config = configs[mode];
2498
+ const baseApiConfig = {
2499
+ url: 'https://api.yourcompany.com/locations',
2500
+ type: 'POST' as const,
2501
+ header: {
2502
+ 'Content-Type': 'application/json',
2503
+ Authorization: 'Bearer YOUR_TOKEN',
2504
+ },
2505
+ additionalParams: {
2506
+ trackingMode: mode,
2507
+ },
2508
+ };
2509
+
2510
+ await ForeGroundLocation.updateLocationSettings({
2511
+ ...config,
2512
+ api: { ...baseApiConfig, ...config.api },
2513
+ });
2514
+ }
2515
+ }
2516
+ ```
2517
+
2518
+ ## Error Handling
2519
+
2520
+ ### Example 8: Comprehensive Error Handling
2521
+
2522
+ ```typescript
2523
+ export class ErrorHandlingLocationService {
2524
+ async startWithErrorHandling() {
2525
+ try {
2526
+ await this.initializeLocationService();
2527
+ } catch (error) {
2528
+ await this.handleLocationError(error);
2529
+ }
2530
+ }
2531
+
2532
+ private async initializeLocationService() {
2533
+ // Check permissions first
2534
+ const permissions = await ForeGroundLocation.checkPermissions();
2535
+
2536
+ if (permissions.location === 'denied') {
2537
+ throw new Error('PERMISSION_PERMANENTLY_DENIED');
2538
+ }
2539
+
2540
+ if (permissions.location !== 'granted') {
2541
+ const result = await ForeGroundLocation.requestPermissions();
2542
+ if (result.location !== 'granted') {
2543
+ throw new Error('PERMISSION_DENIED');
2544
+ }
2545
+ }
2546
+
2547
+ // Test location availability
2548
+ try {
2549
+ await ForeGroundLocation.getCurrentLocation();
2550
+ } catch (error) {
2551
+ throw new Error('LOCATION_NOT_AVAILABLE');
2552
+ }
2553
+
2554
+ // Start service with error handling
2555
+ await ForeGroundLocation.startForegroundLocationService({
2556
+ notification: {
2557
+ title: 'Location Service',
2558
+ text: 'Tracking with error handling',
2559
+ },
2560
+ interval: 30000,
2561
+ priority: 'HIGH_ACCURACY',
2562
+ });
2563
+
2564
+ // Set up error monitoring
2565
+ this.startErrorMonitoring();
2566
+ }
2567
+
2568
+ private async handleLocationError(error: Error) {
2569
+ console.error('Location service error:', error.message);
2570
+
2571
+ switch (error.message) {
2572
+ case 'PERMISSION_DENIED':
2573
+ await this.showPermissionDialog();
2574
+ break;
2575
+
2576
+ case 'PERMISSION_PERMANENTLY_DENIED':
2577
+ await this.showSettingsDialog();
2578
+ break;
2579
+
2580
+ case 'LOCATION_NOT_AVAILABLE':
2581
+ await this.showLocationDisabledDialog();
2582
+ break;
2583
+
2584
+ case 'INVALID_NOTIFICATION':
2585
+ console.error('Invalid notification configuration');
2586
+ break;
2587
+
2588
+ case 'INVALID_PARAMETERS':
2589
+ console.error('Invalid service parameters');
2590
+ break;
2591
+
2592
+ default:
2593
+ await this.showGenericErrorDialog(error.message);
2594
+ }
2595
+ }
2596
+
2597
+ private startErrorMonitoring() {
2598
+ // Monitor service status
2599
+ const statusListener = ForeGroundLocation.addListener('serviceStatus', (status) => {
2600
+ if (!status.isRunning && status.error) {
2601
+ console.error('Service stopped with error:', status.error);
2602
+ this.handleServiceError(status.error);
2603
+ }
2604
+ });
2605
+
2606
+ // Periodic health check
2607
+ setInterval(async () => {
2608
+ try {
2609
+ const isRunning = await ForeGroundLocation.isServiceRunning();
2610
+ if (!isRunning.isRunning) {
2611
+ console.warn('Service is not running, attempting restart');
2612
+ await this.attemptServiceRestart();
2613
+ }
2614
+ } catch (error) {
2615
+ console.error('Health check failed:', error);
2616
+ }
2617
+ }, 60000);
2618
+ }
2619
+
2620
+ private async attemptServiceRestart() {
2621
+ try {
2622
+ await ForeGroundLocation.startForegroundLocationService({
2623
+ notification: {
2624
+ title: 'Location Service Restored',
2625
+ text: 'Resuming location tracking',
2626
+ },
2627
+ interval: 30000,
2628
+ });
2629
+ console.log('Service restarted successfully');
2630
+ } catch (error) {
2631
+ console.error('Failed to restart service:', error);
2632
+ }
2633
+ }
2634
+
2635
+ private async showPermissionDialog() {
2636
+ // Show user-friendly permission request dialog
2637
+ }
2638
+
2639
+ private async showSettingsDialog() {
2640
+ // Guide user to app settings
2641
+ }
2642
+
2643
+ private async showLocationDisabledDialog() {
2644
+ // Guide user to enable device location
2645
+ }
2646
+
2647
+ private async showGenericErrorDialog(errorMessage: string) {
2648
+ // Show generic error with details
2649
+ }
2650
+
2651
+ private handleServiceError(error: string) {
2652
+ // Handle service-specific errors
2653
+ }
2654
+ }
2655
+ ```
2656
+
2657
+ ## Platform-Specific Setup
2658
+
2659
+ ### Android-Specific Configuration
2660
+
2661
+ ```typescript
2662
+ export class AndroidLocationService {
2663
+ async setupAndroidSpecific() {
2664
+ // Check Android version and adjust configuration
2665
+ const isAndroid10Plus = this.isAndroidVersionAtLeast(10);
2666
+
2667
+ if (isAndroid10Plus) {
2668
+ // Android 10+ requires background location permission
2669
+ const permissions = await ForeGroundLocation.checkPermissions();
2670
+
2671
+ if (permissions.backgroundLocation !== 'granted') {
2672
+ // Show explanation before requesting background permission
2673
+ await this.showBackgroundLocationExplanation();
2674
+
2675
+ const result = await ForeGroundLocation.requestPermissions();
2676
+ if (result.backgroundLocation !== 'granted') {
2677
+ console.warn('Background location not granted, some features may be limited');
2678
+ }
2679
+ }
2680
+ }
2681
+
2682
+ // Configure for Android optimization
2683
+ await ForeGroundLocation.startForegroundLocationService({
2684
+ notification: {
2685
+ title: 'Location Service',
2686
+ text: 'Optimized for Android',
2687
+ icon: 'ic_location_android', // Android-specific icon
2688
+ },
2689
+ interval: 15000,
2690
+ priority: 'HIGH_ACCURACY',
2691
+ // Android-specific optimizations
2692
+ distanceFilter: 0, // Let Android handle filtering
2693
+ });
2694
+ }
2695
+
2696
+ private isAndroidVersionAtLeast(version: number): boolean {
2697
+ // Implementation to check Android version
2698
+ return true; // Placeholder
2699
+ }
2700
+
2701
+ private async showBackgroundLocationExplanation() {
2702
+ // Show explanation dialog
2703
+ }
2704
+ }
2705
+ ```
2706
+
2707
+ ### iOS-Specific Configuration
2708
+
2709
+ ```typescript
2710
+ export class iOSLocationService {
2711
+ async setupiOSSpecific() {
2712
+ // iOS has different location permission model
2713
+ await ForeGroundLocation.startForegroundLocationService({
2714
+ notification: {
2715
+ title: 'Location Access',
2716
+ text: 'iOS location service active',
2717
+ },
2718
+ interval: 60000, // iOS may batch updates
2719
+ priority: 'HIGH_ACCURACY',
2720
+ // iOS handles most optimization automatically
2721
+ });
2722
+
2723
+ // iOS-specific monitoring
2724
+ ForeGroundLocation.addListener('locationUpdate', (location) => {
2725
+ // iOS may provide delayed/batched updates
2726
+ console.log('iOS location update:', location);
2727
+ });
2728
+ }
2729
+ }
2730
+ ```
2731
+
2732
+ ## Troubleshooting
2733
+
2734
+ ### Common Issues and Solutions
2735
+
2736
+ ```typescript
2737
+ export class TroubleshootingService {
2738
+ async diagnoseIssues() {
2739
+ console.log('Running location service diagnostics...');
2740
+
2741
+ // 1. Check permissions
2742
+ const permissions = await ForeGroundLocation.checkPermissions();
2743
+ console.log('Permissions:', permissions);
2744
+
2745
+ // 2. Test basic location access
2746
+ try {
2747
+ const location = await ForeGroundLocation.getCurrentLocation();
2748
+ console.log('Basic location access: OK', location);
2749
+ } catch (error) {
2750
+ console.error('Basic location access: FAILED', error);
2751
+ }
2752
+
2753
+ // 3. Check service status
2754
+ const serviceStatus = await ForeGroundLocation.isServiceRunning();
2755
+ console.log('Service running:', serviceStatus.isRunning);
2756
+
2757
+ // 4. Check API service if configured
2758
+ try {
2759
+ const apiStatus = await ForeGroundLocation.getApiServiceStatus();
2760
+ console.log('API Service:', {
2761
+ enabled: apiStatus.isEnabled,
2762
+ bufferSize: apiStatus.bufferSize,
2763
+ healthy: apiStatus.isHealthy,
2764
+ });
2765
+ } catch (error) {
2766
+ console.log('API Service: Not configured or unavailable');
2767
+ }
2768
+
2769
+ // 5. Performance metrics
2770
+ this.startPerformanceMonitoring();
2771
+ }
2772
+
2773
+ private startPerformanceMonitoring() {
2774
+ let updateCount = 0;
2775
+ let lastUpdate = Date.now();
2776
+
2777
+ ForeGroundLocation.addListener('locationUpdate', (location) => {
2778
+ updateCount++;
2779
+ const now = Date.now();
2780
+ const timeSinceLastUpdate = now - lastUpdate;
2781
+ lastUpdate = now;
2782
+
2783
+ console.log(`Update #${updateCount}, ${timeSinceLastUpdate}ms since last update`);
2784
+
2785
+ // Check for issues
2786
+ if (timeSinceLastUpdate > 120000) {
2787
+ // 2 minutes
2788
+ console.warn('Long gap between updates detected');
2789
+ }
2790
+
2791
+ if (location.accuracy > 100) {
2792
+ // 100 meters
2793
+ console.warn('Low accuracy location received:', location.accuracy);
2794
+ }
2795
+ });
2796
+ }
2797
+ }
2798
+ ```
2799
+
2800
+ ### Debug Configuration
2801
+
2802
+ ```typescript
2803
+ export class DebugLocationService {
2804
+ async startDebugMode() {
2805
+ await ForeGroundLocation.startForegroundLocationService({
2806
+ notification: {
2807
+ title: 'DEBUG: Location Service',
2808
+ text: 'Debug mode active - check console',
2809
+ },
2810
+ interval: 10000, // Frequent updates for debugging
2811
+ fastestInterval: 5000,
2812
+ priority: 'HIGH_ACCURACY',
2813
+ distanceFilter: 0, // No filtering for debugging
2814
+
2815
+ api: {
2816
+ url: 'https://httpbin.org/post', // Test endpoint
2817
+ type: 'POST',
2818
+ header: {
2819
+ 'Content-Type': 'application/json',
2820
+ 'X-Debug': 'true',
2821
+ },
2822
+ additionalParams: {
2823
+ debugMode: true,
2824
+ timestamp: new Date().toISOString(),
2825
+ },
2826
+ apiInterval: 1, // Every minute for testing
2827
+ },
2828
+ });
2829
+
2830
+ // Detailed logging
2831
+ ForeGroundLocation.addListener('locationUpdate', (location) => {
2832
+ console.log('DEBUG Location Update:', {
2833
+ coordinates: `${location.latitude}, ${location.longitude}`,
2834
+ accuracy: `${location.accuracy}m`,
2835
+ timestamp: location.timestamp,
2836
+ hasAltitude: !!location.altitude,
2837
+ hasBearing: !!location.bearing,
2838
+ hasSpeed: !!location.speed,
2839
+ });
2840
+ });
2841
+
2842
+ // Monitor API service in detail
2843
+ setInterval(async () => {
2844
+ const status = await ForeGroundLocation.getApiServiceStatus();
2845
+ console.log('DEBUG API Status:', status);
2846
+ }, 30000);
2847
+ }
2848
+ }
2849
+ ```
2850
+
2851
+ This comprehensive guide covers all aspects of setting up and using the Foreground Location Plugin with API service integration. Each example is production-ready and includes proper error handling and best practices.