adaptive_location_tracker 0.1.5 copy "adaptive_location_tracker: ^0.1.5" to clipboard
adaptive_location_tracker: ^0.1.5 copied to clipboard

PlatformAndroid

A battery-efficient adaptive location tracker with offline sync, Kalman filtering, and foreground service support.

Adaptive Location Tracker 📍 #

A "Gold Standard" location tracking plugin for Flutter, designed for battery efficiency, high accuracy, and offline resilience. It creates a foreground service on Android to track location reliably in the background, making it perfect for field force, delivery, and logistics applications.

✨ Features #

  • 🔋 Battery Efficient: Uses Google's FusedLocationProviderClient and partial wake locks to ensure reliability without excessive drain.
  • 🧠 Intelligent Filtering:
    • Spiderweb Prevention: Automatically "Locks" location when stationary (e.g., inside a building) to prevent random GPS jumps.
    • Breakout Detection: Uses a sequence of verified moves to resume tracking, ensuring accuracy in rural or urban canyon areas.
    • Impossible Speed Filter: Rejects impossible jumps in location (e.g., GPS glitching 500m in 1 second).
  • 📡 Robust Syncing:
    • Batch Uploads: Sends multiple locations (up to 100) in a single HTTP request to save battery and reduce server load.
    • Offline Buffer: Automatically saves coordinates to a local SQLite database when the network is unavailable.
    • Exponential Backoff: Retries failed syncs with increasing delays (2s, 4s, 8s...) to handle server downtime gracefully.
  • ⚠️ Status Reporting: Automatically reports to a specific URL when the user turns GPS on or off.
  • 🏁 Managed Checkout: Dedicated checkout flow that attempts to flush all pending data and reports final success or failure through events.
  • 🌐 Dual Mode: Supports both HTTP/REST and WebSockets for real-time tracking.

🚀 Installation #

Add the package to your pubspec.yaml:

dependencies:
  adaptive_location_tracker: ^0.1.4

Android Setup #

The plugin handles most permissions, but ensure your AndroidManifest.xml doesn't conflict. The plugin requires:

  • ACCESS_FINE_LOCATION
  • ACCESS_BACKGROUND_LOCATION (Mandatory for background tracking)
  • POST_NOTIFICATIONS (Mandatory for showing foreground service notifications on Android 13+)
  • ACCESS_NETWORK_STATE (To safely evaluate data connection changes)
  • INTERNET (For REST/WebSocket uploads)
  • FOREGROUND_SERVICE
  • FOREGROUND_SERVICE_LOCATION
  • ACTIVITY_RECOGNITION (for Motion Detection)
  • REQUEST_IGNORE_BATTERY_OPTIMIZATIONS (Highly recommended)

🎨 Custom Notification Icons #

By default, the notification will automatically load and display your host application's primary launcher icon. If you want a dedicated, flat status bar notification icon, simply place a transparent drawable named notification_icon (e.g., notification_icon.png) inside your Android project's drawable resources (android/app/src/main/res/drawable/). The package will automatically resolve it and display it!

⚠️ Important: Android Background Restrictions #

🔋 Battery Optimizations #

Android OS is very aggressive at killing background services to save power. Recommendation:

  1. The app should request to ignore battery optimizations: Permission.ignoreBatteryOptimizations.request().
  2. Guide users to set the app to "Don't Optimize" or "Unrestricted" in system settings.

📱 Location "Always" #

On Android 11+, users must manually select "Allow all the time" in the app's location settings. Background tracking will fail or be severely throttled if only "While using the app" is selected.


📖 Usage #

1. Start Tracking #

Call start() with your configuration. It returns a bool indicating if the service was successfully initiated.

bool success = await AdaptiveLocationTracker.start(
  url: 'https://your-api.com/v1/trace',
  reportLocationUrl: 'https://your-api.com/v1/report-location',
  headers: {'Authorization': 'Bearer YOUR_TOKEN'},
  intervalSeconds: 15,
  extraData: {'user_id': 101},
);

2. Listen to Real-time Events (Stream) #

Subscribe to the static eventsStream broadcast to receive real-time updates from the background service (such as smooth coordinates, motion state transitions, sync successes, checkout outcomes, or runtime errors):

import 'dart:async';
import 'package:adaptive_location_tracker/adaptive_location_tracker.dart';

StreamSubscription<Map<String, dynamic>>? _subscription;

void startListening() {
  _subscription = AdaptiveLocationTracker.eventsStream.listen((event) {
    final String type = event['type'];
    
    switch (type) {
      case 'location':
        // Real-time Kalman-smoothed approved coordinate
        print("Approved: ${event['latitude']}, ${event['longitude']} (Accuracy: ${event['accuracy']}m)");
        break;
        
      case 'trip_state':
        // State transition updates: 'MOVING' or 'STATIONARY'
        print("Trip State changed to: ${event['state']}");
        break;
        
      case 'sync_success':
        // Successful remote batch sync event
        print("Successfully flushed ${event['count']} records to the server.");
        break;

      case 'checkout_success':
        // Checkout completed and all pending points were flushed
        print(event['message']);
        break;
        
      case 'error':
        // Real-time error reports
        print("Native error [${event['code']}]: ${event['message']}");
        break;
    }
  });
}

void stopListening() {
  _subscription?.cancel();
}

3. Checkout (Safe Stop) #

Starts a flush of all locally stored points before shutting down. Use this for "End Shift" buttons.

bool checkoutStarted = await AdaptiveLocationTracker.checkout();

checkout() returning true means the checkout flow was started successfully. Final result arrives later on eventsStream:

  • checkout_success: all pending points were flushed and the service stopped
  • error with CHECKOUT_FLUSH_FAILED: pending data could not be fully flushed, so the service stays active

4. Immediate Stop #

Stops the service immediately without flushing the database.

await AdaptiveLocationTracker.stop();

📡 Backend Implementation #

A. Tracking Endpoint (url) #

Receives an Array of location objects.

[
  {
    "latitude": 12.9716,
    "longitude": 77.5946,
    "timestamp": 1715065200000,
    "accuracy": 15.2,
    "user_id": 101
  }
]

Important:

  • The request body is a top-level JSON array, not a wrapped object like { "locations": [...] }.
  • extraData is flattened into each location object before sending.
  • Do not use reserved keys inside extraData, because they can conflict with core fields:
    • latitude
    • longitude
    • timestamp
    • accuracy

B. Status Report Endpoint (reportLocationUrl) #

Receives a single status Object.

{
  "latitude": 12.9716,
  "longitude": 77.5946,
  "remarks": "Location disabled by user"
}

⚙️ Core Logic (State Machine) #

  1. MOVING State: Records points if they are >10m apart and meet accuracy thresholds.
  2. STATIONARY State: The service "locks" to a clean point and ignores GPS drift until a significant move (30m+) is detected.
  3. Sync Scheduler: Runs every intervalSeconds. It fetches pending data, sends a batch, and deletes them only after a 200 OK response.

Event Codes #

Common error event codes emitted by the Android service:

  • LOCATION_DISABLED
  • LOCATION_PERMISSION_MISSING
  • LOCATION_REQUEST_FAILED
  • LOCATION_TEMPORARILY_UNAVAILABLE
  • LOCATION_SECURITY_ERROR
  • SYNC_FAILURE
  • WEBSOCKET_FAILURE
  • CHECKOUT_FLUSH_FAILED

Transport Reliability #

HTTP / REST mode #

  • Batched locations are sent with HTTP POST.
  • Local records are deleted only after the server returns a successful 2xx response.
  • This is the recommended mode when reliable delivery matters.

WebSocket mode #

  • WebSocket mode is suitable for live, low-latency streaming.
  • The current implementation does not use server ACK messages to confirm delivery before considering a batch sent.
  • For that reason, WebSocket mode should be treated as best-effort live transport unless your backend and plugin are extended with explicit ACK semantics.
  • If your use case requires strong delivery guarantees, prefer HTTP mode.

❤️ Credits #

Built for high-reliability field operations with advanced jitter filtering and offline resilience.

4
likes
160
points
501
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A battery-efficient adaptive location tracker with offline sync, Kalman filtering, and foreground service support.

Repository (GitHub)

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on adaptive_location_tracker

Packages that implement adaptive_location_tracker