tracelet 3.2.19 copy "tracelet: ^3.2.19" to clipboard
tracelet: ^3.2.19 copied to clipboard

Production-grade background geolocation for Flutter. Battery-conscious tracking, geofencing, SQLite persistence, HTTP sync, and headless execution for iOS & Android.

example/main.dart

// ignore_for_file: avoid_print

import 'package:tracelet/tracelet.dart' as tl;

/// Minimal example demonstrating Tracelet background geolocation.
Future<void> main() async {
  // 1. Subscribe to location events.
  tl.Tracelet.onLocation((location) {
    print(
      '๐Ÿ“ ${location.coords.latitude}, ${location.coords.longitude} '
      'ยท accuracy: ${location.coords.accuracy}m',
    );
  });

  // 2. Initialize the plugin with a configuration.
  final state = await tl.Tracelet.ready(
    const tl.Config(logger: tl.LoggerConfig(logLevel: tl.LogLevel.verbose)),
  );

  print(
    'Tracelet ready โ€” enabled: ${state.enabled}, '
    'tracking: ${state.trackingMode}',
  );

  // 3. Start tracking.
  await tl.Tracelet.start();
}

// ---------------------------------------------------------------------------
// One-Shot Location Examples
// ---------------------------------------------------------------------------

/// Example: Single location fetch โ€” no continuous tracking, no persistence.
///
/// This is the simplest way to get the device's current location without
/// starting background tracking or showing a foreground notification.
Future<void> singleLocationExample() async {
  // Initialize with foreground service DISABLED (Android).
  // No persistent notification will be shown.
  await tl.Tracelet.ready(
    const tl.Config(
      android: tl.AndroidConfig(
        foregroundService: tl.ForegroundServiceConfig(
          enabled: false, // No foreground notification on Android.
        ),
      ),
    ),
  );

  // Ensure location permission is granted before requesting.
  final authStatus = await tl.Tracelet.requestLocationAuthorization();
  if (authStatus != tl.AuthorizationStatus.whenInUse &&
      authStatus != tl.AuthorizationStatus.always) {
    print('โš ๏ธ Location permission denied (status=$authStatus)');
    return;
  }

  // Fetch a single location โ€” does NOT start continuous tracking.
  final location = await tl.Tracelet.getCurrentPosition(
    desiredAccuracy: tl.DesiredAccuracy.high,
    timeout: 30,
    persist: false, // Don't store in local database.
  );

  print(
    '๐Ÿ“ Single fix: ${location.coords.latitude}, '
    '${location.coords.longitude}  '
    'accuracy: ${location.coords.accuracy}m',
  );
}

/// Example: Best-of-N samples โ€” collect multiple GPS fixes and return the
/// one with the best (lowest) horizontal accuracy.
///
/// Useful for check-in flows, geocoding, or any scenario where you need
/// high confidence in a single reading.
Future<void> bestOfThreeSamplesExample() async {
  await tl.Tracelet.ready(
    const tl.Config(
      android: tl.AndroidConfig(
        foregroundService: tl.ForegroundServiceConfig(enabled: false),
      ),
    ),
  );

  // Ensure location permission is granted before requesting.
  final authStatus = await tl.Tracelet.requestLocationAuthorization();
  if (authStatus != tl.AuthorizationStatus.whenInUse &&
      authStatus != tl.AuthorizationStatus.always) {
    print('โš ๏ธ Location permission denied (status=$authStatus)');
    return;
  }

  // Collect 3 GPS samples, return the most accurate one.
  final location = await tl.Tracelet.getCurrentPosition(
    desiredAccuracy: tl.DesiredAccuracy.high,
    timeout: 30,
    samples: 3,
    persist: false,
  );

  print(
    '๐Ÿ“ Best of 3: ${location.coords.latitude}, '
    '${location.coords.longitude}  '
    'accuracy: ${location.coords.accuracy}m',
  );
}

/// Example: Last known location โ€” instant retrieval from OS cache.
///
/// No GPS hardware is activated. Returns null if the OS has no cached
/// location (e.g. fresh device boot with no prior location providers used).
Future<void> lastKnownLocationExample() async {
  await tl.Tracelet.ready(
    const tl.Config(
      android: tl.AndroidConfig(
        foregroundService: tl.ForegroundServiceConfig(enabled: false),
      ),
    ),
  );

  // Ensure location permission is granted before requesting.
  final authStatus = await tl.Tracelet.requestLocationAuthorization();
  if (authStatus != tl.AuthorizationStatus.whenInUse &&
      authStatus != tl.AuthorizationStatus.always) {
    print('โš ๏ธ Location permission denied (status=$authStatus)');
    return;
  }

  final location = await tl.Tracelet.getLastKnownLocation();

  if (location == null) {
    print('โš ๏ธ No cached location available');
  } else {
    print(
      '๐Ÿ“ Last known: ${location.coords.latitude}, '
      '${location.coords.longitude}  '
      'accuracy: ${location.coords.accuracy}m',
    );
  }
}

// ---------------------------------------------------------------------------
// Advanced Configuration Examples โ€” New Features
// ---------------------------------------------------------------------------

/// Example: Elasticity control โ€” disable speed-based distance filter scaling.
///
/// By default, Tracelet dynamically adjusts the distance filter based on
/// speed. Disable elasticity for a fixed `distanceFilter` regardless of speed.
Future<void> elasticityExample() async {
  await tl.Tracelet.ready(
    const tl.Config(
      geo: tl.GeoConfig(
        distanceFilter: 50,
        // Disable elasticity: record at exactly every 50m regardless of speed.
        disableElasticity: true,
      ),
    ),
  );
  await tl.Tracelet.start();
}

/// Example: Location filtering โ€” reject GPS spikes and low-accuracy readings.
///
/// The [tl.LocationFilter] denoises raw GPS samples before they are recorded.
/// This helps eliminate noise, phantom jumps, and low-quality readings.
Future<void> locationFilterExample() async {
  await tl.Tracelet.ready(const tl.Config());
  await tl.Tracelet.start();
}

/// Example: Auto-stop โ€” automatically stop tracking after N minutes.
///
/// Useful for time-boxed tracking sessions (e.g., a 30-minute workout).
Future<void> autoStopExample() async {
  await tl.Tracelet.ready(
    const tl.Config(
      geo: tl.GeoConfig(
        // Automatically stop tracking after 30 minutes. Use -1 to disable.
        stopAfterElapsedMinutes: 30,
      ),
    ),
  );
  await tl.Tracelet.start();
  print('Tracking will auto-stop after 30 minutes');
}

/// Example: Persistence control โ€” choose what to persist and retention limits.
///
/// Fine-tune what goes into the SQLite database and how long records are kept.
Future<void> persistenceConfigExample() async {
  await tl.Tracelet.ready(
    const tl.Config(
      persistence: tl.PersistenceConfig(
        // Auto-prune records older than 7 days. Use -1 for unlimited.
        maxDaysToPersist: 7,
        // Auto-prune when exceeding 5000 records. Use -1 for unlimited.
        maxRecordsToPersist: 5000,
      ),
    ),
  );
  await tl.Tracelet.start();
}

/// Example: Geofence high-accuracy mode โ€” use continuous GPS in geofence-only mode.
///
/// By default, `startGeofences()` uses the platform's passive geofence monitoring
/// (battery friendly but less precise). Enable high-accuracy mode to run the
/// full GPS + motion pipeline even in geofence-only mode.
Future<void> geofenceHighAccuracyExample() async {
  await tl.Tracelet.ready(
    const tl.Config(
      android: tl.AndroidConfig(
        // Enable high-accuracy geofence monitoring (Android only).
        geofenceModeHighAccuracy: true,
      ),
    ),
  );

  // Add a geofence first
  await tl.Tracelet.addGeofence(
    const tl.Geofence(
      identifier: 'office',
      latitude: 37.4220,
      longitude: -122.0841,
      radius: 200,
    ),
  );

  // Start geofence-only mode with high-accuracy GPS active.
  await tl.Tracelet.startGeofences();
}

/// Example: Timestamp metadata โ€” append extra timing info to each location.
///
/// When enabled, each location record includes additional timestamp fields
/// useful for debugging timing issues and analyzing location pipeline latency.
Future<void> timestampMetaExample() async {
  await tl.Tracelet.ready(
    const tl.Config(geo: tl.GeoConfig(enableTimestampMeta: true)),
  );

  tl.Tracelet.onLocation((loc) {
    print('๐Ÿ“ ${loc.coords.latitude}, ${loc.coords.longitude}');
    // With enableTimestampMeta: true, the location record contains
    // additional fields for arrival time at the platform layer.
  });

  await tl.Tracelet.start();
}

/// Example: Motion detection tuning โ€” adjust activity recognition sensitivity.
///
/// Fine-tune how aggressively Tracelet detects motion state changes.
Future<void> motionTuningExample() async {
  await tl.Tracelet.ready(const tl.Config());
  await tl.Tracelet.start();
}

/// Example: iOS prevent suspend โ€” keep the app alive in background.
///
/// Plays a silent audio clip to prevent iOS from suspending the app.
/// Uses minimal battery but ensures continuous background execution.
Future<void> preventSuspendExample() async {
  await tl.Tracelet.ready(
    const tl.Config(
      app: tl.AppConfig(stopOnTerminate: false, startOnBoot: true),
      ios: tl.IosConfig(
        // iOS only: prevent iOS from suspending the app.
        preventSuspend: true,
      ),
    ),
  );
  await tl.Tracelet.start();
}

/// Example: Android schedule with AlarmManager โ€” exact-time scheduling.
///
/// Uses AlarmManager for precise schedule execution instead of the default
/// JobScheduler/WorkManager which may defer execution.
Future<void> scheduleAlarmManagerExample() async {
  await tl.Tracelet.ready(
    const tl.Config(
      app: tl.AppConfig(
        stopOnTerminate: false,
        startOnBoot: true,
        // Define a schedule: Mon-Fri, 9am-5pm
        schedule: ['1-5 09:00-17:00'],
      ),
      android: tl.AndroidConfig(
        // Android only: use AlarmManager for exact schedule timing.
        scheduleUseAlarmManager: true,
      ),
    ),
  );
  // The schedule will auto-start/stop tracking at the defined times.
}

/// Example: Wi-Fi-only sync โ€” disable auto-sync on cellular connections.
///
/// Useful for bandwidth-conscious apps that should only sync on Wi-Fi.
Future<void> wifiOnlySyncExample() async {
  await tl.Tracelet.ready(
    const tl.Config(
      http: tl.HttpConfig(
        url: 'https://example.com/locations',
        // Only sync when connected to Wi-Fi, not on cellular.
        disableAutoSyncOnCellular: true,
      ),
    ),
  );
  await tl.Tracelet.start();
}

/// Example: Dart-side permission flow โ€” check, request, handle denial.
///
/// No native dialogs are shown. The OS permission prompt is the only native
/// UI. If permanently denied, guide the user to Settings from Dart.
Future<void> permissionFlowExample() async {
  // 1. Check current status without triggering any dialog.
  final status = await tl.Tracelet.getLocationAuthorization();
  print('Current permission status: $status');

  if (status == tl.AuthorizationStatus.notDetermined ||
      status == tl.AuthorizationStatus.denied) {
    // notDetermined or denied (can ask again) โ†’ request foreground.
    final result = await tl.Tracelet.requestLocationAuthorization();
    print('After request: $result');

    if (result == tl.AuthorizationStatus.deniedForever) {
      // Permanently denied โ€” show YOUR OWN Dart dialog here, e.g.:
      // showDialog(context, builder: (_) => AlertDialog(
      //   title: Text('Permission Required'),
      //   content: Text('Open Settings to enable location access.'),
      //   actions: [
      //     TextButton(onPressed: () => Tracelet.openAppSettings(), ...),
      //   ],
      // ));
      print('Permanently denied โ€” open settings');
      await tl.Tracelet.openAppSettings();
      return;
    }

    if (result == tl.AuthorizationStatus.whenInUse) {
      // Foreground granted โ€” request background upgrade.
      final bgResult = await tl.Tracelet.requestLocationAuthorization();
      print('Background request: $bgResult');
    }
  } else if (status == tl.AuthorizationStatus.deniedForever) {
    // Already permanently denied โ€” guide user to settings.
    await tl.Tracelet.openAppSettings();
    return;
  }

  // Permission is now whenInUse (2) or always (3) โ€” safe to start.
  await tl.Tracelet.ready(
    const tl.Config(
      app: tl.AppConfig(stopOnTerminate: false, startOnBoot: true),
    ),
  );
  await tl.Tracelet.start();
}

/// Example: Full-featured config โ€” combining all new features.
///
/// Demonstrates how all configuration options work together.
Future<void> fullFeaturedExample() async {
  tl.Tracelet.onLocation((loc) {
    print(
      '๐Ÿ“ ${loc.coords.latitude}, ${loc.coords.longitude} '
      'acc=${loc.coords.accuracy}m',
    );
  });

  await tl.Tracelet.ready(
    const tl.Config(
      geo: tl.GeoConfig(enableTimestampMeta: true),
      app: tl.AppConfig(stopOnTerminate: false, startOnBoot: true),
      http: tl.HttpConfig(
        url: 'https://example.com/locations',
        disableAutoSyncOnCellular: true,
      ),
      persistence: tl.PersistenceConfig(
        maxDaysToPersist: 7,
        maxRecordsToPersist: 5000,
      ),
      logger: tl.LoggerConfig(logLevel: tl.LogLevel.verbose, debug: true),
    ),
  );

  await tl.Tracelet.start();
}
38
likes
0
points
6.26k
downloads

Documentation

Documentation

Publisher

verified publisherikolvi.com

Weekly Downloads

Production-grade background geolocation for Flutter. Battery-conscious tracking, geofencing, SQLite persistence, HTTP sync, and headless execution for iOS & Android.

Homepage
Repository (GitHub)
View/report issues

Topics

#geolocation #location #background #geofencing #tracking

Funding

Consider supporting this project:

github.com
www.buymeacoffee.com
thanks.dev
www.patreon.com

License

unknown (license)

Dependencies

collection, flutter, meta, tracelet_android, tracelet_ios, tracelet_platform_interface, tracelet_web

More

Packages that depend on tracelet

Packages that implement tracelet