🚀 Guía de migración: flutter_background_geolocation → Tracelet
¿Cambiar de flutter_background_geolocation a Tracelet? ¡Gran elección! Tracelet es una alternativa totalmente de código abierto (Apache 2.0) con una API compatible 1:1, además de extras como filtrado Kalman, detección simulada, zonas de privacidad y más. Sin claves de licencia, sin SDK propietarios, código fuente completo.
💡 Esta guía siempre refleja la versión actual.
⚡ Carrera rápida de 3 pasos
En serio, es así de rápido.
Paso 1: intercambiar la dependencia:
# Before
dependencies:
flutter_background_geolocation: ^5.x.xDespués ✨
dependencies:
tracelet: ^3.6.14
Paso 2: Actualizar importaciones:
// Before
import 'package:flutter_background_geolocation/flutter_background_geolocation.dart' as bg;
// After — short & sweet ✅
import 'package:tracelet/tracelet.dart' as tl;Paso 3: busque y reemplace el nombre de la clase:
// Before
bg.BackgroundGeolocation.ready(bg.Config(...));
// After
tl.Tracelet.ready(tl.Config.balanced().copyWith(...));Eso es literalmente todo. Cada método, cada evento, cada devolución de llamada: compatible 1:1. El resto de esta guía es sólo una hoja de referencia para los detalles.
🏗️ Configuración: de plana a estructurada
El complemento anterior utiliza un único Config() plano con todos los campos en un nivel. Tracelet los organiza en secciones lógicas, lo que hace que las configuraciones grandes sean mucho más fáciles de leer y mantener.
// Before — flat config
bg.Config(
desiredAccuracy: bg.Config.DESIRED_ACCURACY_HIGH,
distanceFilter: 10.0,
stopOnTerminate: false,
startOnBoot: true,
stopTimeout: 5,
url: 'https://api.example.com/locations',
batchSync: true,
autoSync: true,
headers: {'Authorization': 'Bearer $token'},
heartbeatInterval: 60,
notification: bg.Notification(title: 'Tracking', text: 'Active'),
debug: true,
logLevel: bg.Config.LOG_LEVEL_VERBOSE,
);
// After — organized by section 🏠
tl.Config(
geo: tl.GeoConfig(
desiredAccuracy: tl.DesiredAccuracy.high, // typed enums!
distanceFilter: 10.0,
),
app: tl.AppConfig(
stopOnTerminate: false,
startOnBoot: true,
heartbeatInterval: 60,
),
android: tl.AndroidConfig(
foregroundService: tl.ForegroundServiceConfig(
notificationTitle: 'Tracking',
notificationText: 'Active',
),
),
motion: tl.MotionConfig(
stopTimeout: 5,
),
http: tl.HttpConfig(
url: 'https://api.example.com/locations',
batchSync: true,
autoSync: true,
headers: {'Authorization': 'Bearer $token'},
),
logger: tl.LoggerConfig(
debug: true,
logLevel: tl.LogLevel.verbose, // readable enum instead of int constants
),
);Las secciones de configuración de un vistazo:
geo→GeoConfig— Precisión, filtro de distancia, elasticidad, modo periódico, filtro de Kalman, detección simuladaapp→AppConfig— Ciclo de vida, latidos, programaciónandroid→AndroidConfig— 🆕 Solo Android: notificación de servicio en primer plano, intervalos de actualización de ubicación, AlarmManager, estrategias periódicasios→IosConfig— 🆕 Solo iOS: tipo de actividad, sesiones en segundo plano, evitar suspensiónmotion→MotionConfig— Tiempo de espera de parada, reconocimiento de actividad, modo solo acelerómetrohttp→HttpConfig: URL de sincronización, encabezados, procesamiento por lotes, reintento de retroceso, modo solo Wi-Filogger→LoggerConfig— Nivel de registro, días máximos, sonidos de depuracióngeofence→GeofenceConfig— Radio de proximidad, disparador inicial, modo knock-outpersistence→PersistenceConfig— Modo persistente, máximo de días/registros, plantillasaudit→AuditConfig— 🆕 Cadena hash SHA-256 — porque la seguridad es importanteprivacyZone→PrivacyZoneConfig— 🆕 Motor de zonas de privacidad — El mejor amigo del RGPDsecurity→SecurityConfig— 🆕 Cifrado de base de datos en reposo (encryptDatabase)attestation→AttestationConfig— 🆕 Verificaciones de integridad/certificación del dispositivo
🗺️ La hoja de referencia de la gran configuración
No te preocupes, cada campo tiene un mapeo 1:1. Aquí está tu Piedra Rosetta.
Ubicación y seguimiento → GeoConfig
Before → Tracelet
─────────────────────────────────────────────────────────────
desiredAccuracy (int: -2…100) → geo.desiredAccuracy (DesiredAccuracy enum)
.high / .medium / .low / .veryLow / .passive
distanceFilter → geo.distanceFilter (default 10m)
stationaryRadius → geo.stationaryRadius (default 25m)
locationTimeout → geo.locationTimeout (default 60s)
disableElasticity → geo.disableElasticity
elasticityMultiplier → geo.elasticityMultiplier (default 1.0)
stopAfterElapsedMinutes → geo.stopAfterElapsedMinutes (-1 = disabled)
enableTimestampMeta → geo.enableTimestampMeta
maxMonitoredGeofences → geo.maxMonitoredGeofences (-1 = platform default)Campos específicos de Android → AndroidConfig:
Before → Tracelet
─────────────────────────────────────────────────────────────
locationUpdateInterval → android.locationUpdateInterval (1000ms)
fastestLocationUpdateInterval → android.fastestLocationUpdateInterval (500ms)
deferTime → android.deferTime
allowIdenticalLocations → android.allowIdenticalLocations
geofenceModeHighAccuracy → geofence.geofenceModeHighAccuracy (cross-platform; android.* is deprecated)
scheduleUseAlarmManager → android.scheduleUseAlarmManagerCampos específicos de iOS → IosConfig:
Before → Tracelet
─────────────────────────────────────────────────────────────
activityType → ios.activityType (LocationActivityType enum)
useSignificantChangesOnly → ios.useSignificantChangesOnly
showsBackgroundLocationIndicator → ios.showsBackgroundLocationIndicator
pausesLocationUpdatesAutomatically → ios.pausesLocationUpdatesAutomatically
locationAuthorizationRequest → ios.locationAuthorizationRequest
disableLocationAuthorizationAlert → ios.disableLocationAuthorizationAlert
preventSuspend → ios.preventSuspend🆕 Campos GeoConfig exclusivos de Tracelet:
geo.enableAdaptiveMode— Adapta el filtro de distancia por actividad + batería + velocidadgeo.periodicLocationInterval: 900 predeterminados (15 min)geo.periodicDesiredAccuracy:.mediumpredeterminadogeo.filter(LocationFilter) — Kalman, detección simulada, umbrales de precisión
🧹 Filtro de ubicación → LocationFilter (¡exclusivo de Tracelet!)
- 🆕
filter.policy—LocationFilterPolicy.adjust/.ignore/.discard - 🆕
filter.useKalmanFilter— Filtro Kalman extendido de 4 estados: suaviza el ruido del GPS como un profesional - 🆕
filter.mockDetectionLevel—.disabled/.basic/.heuristic— detecta esas ubicaciones falsas - 🆕
filter.rejectMockLocations— Ubicaciones simuladas de rechazo automático - 🆕
filter.maxImpliedSpeed— Filtro de picos — “no, el usuario NO se teletransportó” - 🆕
filter.trackingAccuracyThreshold— Precisión mínima para aceptar - 🆕
filter.odometerAccuracyThreshold— Precisión mínima para actualizaciones del odómetro
Detección de movimiento → MotionConfig
Before → Tracelet
─────────────────────────────────────────────────────────────
stopTimeout → motion.stopTimeout (default 5 min)
motionTriggerDelay → motion.motionTriggerDelay
disableMotionActivityUpdates → motion.disableMotionActivityUpdates
(set true for accelerometer-only, no permission!)
isMoving → motion.isMoving (initial state)
activityRecognitionInterval → motion.activityRecognitionInterval (10000ms)
minimumActivityRecognitionConfidence → motion.minimumActivityRecognitionConfidence (75)
disableStopDetection → motion.disableStopDetection
stopDetectionDelay → motion.stopDetectionDelay
stopOnStationary → motion.stopOnStationary
triggerActivities → motion.activityTypes (Set<ActivityType>)🆕 Campos MotionConfig exclusivos de Tracelet:
motion.motionDetectionMode—.accelerometer/.speed/.smart— cómo se detecta el movimiento (inteligente = acelerómetro y velocidad del GPS; recomendado)motion.shakeThreshold: ajuste solo del acelerómetro (predeterminado 2.5)motion.stillThreshold: ajuste solo del acelerómetro (predeterminado 0.4)motion.stillSampleCount: ajuste solo del acelerómetro (predeterminado 25)motion.speedMovingThreshold/motion.speedStationaryDelay/motion.speedWakeConfirmCount— ajuste del modo de velocidad (utilizado por.speed/.smart)motion.stationaryTrackingMode/motion.stationaryPeriodicInterval/motion.stationaryPeriodicAccuracy: qué hacer una vez estacionario (arreglos periódicos frente a geocercas)
Aplicación → AppConfig
Before → Tracelet
─────────────────────────────────────────────────────────────
stopOnTerminate → app.stopOnTerminate (default true)
startOnBoot → app.startOnBoot (default false)
heartbeatInterval → app.heartbeatInterval (default 60s)
schedule → app.schedule (cron-like expressions)Nota:
scheduleUseAlarmManager→android.scheduleUseAlarmManager|preventSuspend→ios.preventSuspend
🔔 Notificación de servicio en primer plano → AndroidConfig.foregroundService
Importante (cambio 2.x.x): La notificación del servicio en primer plano ahora está configurada en
android.foregroundService(unAndroidConfig), no enapp. Este es un concepto exclusivo de Android.
Before (Notification) → Tracelet (AndroidConfig.foregroundService)
─────────────────────────────────────────────────────────────
title → android.foregroundService.notificationTitle
text → android.foregroundService.notificationText
color → android.foregroundService.notificationColor
smallIcon → android.foregroundService.notificationSmallIcon
largeIcon → android.foregroundService.notificationLargeIcon
priority → android.foregroundService.notificationPriority
channelName → android.foregroundService.channelName
channelId → android.foregroundService.channelId
sticky → android.foregroundService.notificationOngoing
actions → android.foregroundService.actions
enabled → android.foregroundService.enabledSincronización HTTP → HttpConfig
Before → Tracelet
─────────────────────────────────────────────────────────────
url → http.url (null = sync disabled)
method → http.method (HttpMethod.post / .put)
headers → http.headers
httpRootProperty → http.httpRootProperty (default 'location')
batchSync → http.batchSync
maxBatchSize → http.maxBatchSize
autoSync → http.autoSync
autoSyncThreshold → http.autoSyncThreshold
httpTimeout → http.httpTimeout (default 60000ms)
params → http.params
extras → http.extras
locationsOrderDirection → http.locationsOrderDirection (LocationOrder enum)🆕 Campos HttpConfig exclusivos de Tracelet:
http.disableAutoSyncOnCellular: sincronización solo por Wi-Fi: ¡guarda ese plan de datos!http.maxRetries: valor predeterminado 10, con retroceso exponencial + fluctuaciónhttp.retryBackoffBase: predeterminado 1000 mshttp.retryBackoffCap: predeterminado 300000 ms (5 min)
Geocercas → GeofenceConfig
Before → Tracelet
─────────────────────────────────────────────────────────────
geofenceProximityRadius → geofence.geofenceProximityRadius (default 1000m)
geofenceInitialTriggerEntry → geofence.geofenceInitialTriggerEntry (default true)- 🆕
geofence.geofenceModeKnockOut— Elimina automáticamente la geovalla después de la primera SALIDA: ¡una y listo!
Persistencia → PersistenceConfig
Before → Tracelet
─────────────────────────────────────────────────────────────
persistMode → persistence.persistMode (.all / .location / .geofence / .none)
maxDaysToPersist → persistence.maxDaysToPersist (-1 = forever)
maxRecordsToPersist → persistence.maxRecordsToPersist (-1 = unlimited)
locationTemplate → persistence.locationTemplate (Mustache-style)
geofenceTemplate → persistence.geofenceTemplate (Mustache-style)
disableProviderChangeRecord → persistence.disableProviderChangeRecord
extras → persistence.extrasRegistro → LoggerConfig
Before → Tracelet
─────────────────────────────────────────────────────────────
logLevel (int const) → logger.logLevel (.verbose / .debug / .info / .warning / .error)
logMaxDays → logger.logMaxDays (default 3)
debug → logger.debug (alert sounds — fun at demos, terrifying at 3 AM)🔐 Registro de auditoría → AuditConfig (exclusivo de Tracelet)
audit.enabled—falsede forma predeterminada. Cadena de hash SHA-256 en cada ubicación: manipulación = reventadaaudit.hashAlgorithm—HashAlgorithm.sha256audit.includeExtrasInHash—falsepor defecto
🛡️ Zonas de privacidad → PrivacyZoneConfig (exclusivo de Tracelet)
privacyZone.enabled—falsede forma predeterminada. Habilite el motor de zona de privacidad.
🎯 Constantes de precisión: ¡enumeraciones escritas!
Before (int constants) → Tracelet (typed enum)
─────────────────────────────────────────────────────────────
Config.DESIRED_ACCURACY_NAVIGATION → DesiredAccuracy.high
Config.DESIRED_ACCURACY_HIGH → DesiredAccuracy.high
Config.DESIRED_ACCURACY_MEDIUM → DesiredAccuracy.medium
Config.DESIRED_ACCURACY_LOW → DesiredAccuracy.low
Config.DESIRED_ACCURACY_VERY_LOW → DesiredAccuracy.veryLow
Config.DESIRED_ACCURACY_LOWEST → DesiredAccuracy.passive📡 Eventos: mismos nombres, menos escritura
Las 14 transmisiones de eventos se mapean 1:1. Simplemente cambia el prefijo:
Before → Tracelet Callback Type
─────────────────────────────────────────────────────────────────────────
onLocation(cb) → onLocation(cb) Location
onMotionChange(cb) → onMotionChange(cb) Location
onActivityChange(cb) → onActivityChange(cb) ActivityChangeEvent
onProviderChange(cb) → onProviderChange(cb) ProviderChangeEvent
onGeofence(cb) → onGeofence(cb) GeofenceEvent
onGeofencesChange(cb) → onGeofencesChange(cb) GeofencesChangeEvent
onHeartbeat(cb) → onHeartbeat(cb) HeartbeatEvent
onHttp(cb) → onHttp(cb) HttpEvent
onSchedule(cb) → onSchedule(cb) State
onPowerSaveChange(cb) → onPowerSaveChange(cb) bool
onConnectivityChange(cb) → onConnectivityChange(cb) ConnectivityChangeEvent
onEnabledChange(cb) → onEnabledChange(cb) bool
onNotificationAction(cb) → onNotificationAction(cb) String
onAuthorization(cb) → onAuthorization(cb) AuthorizationEvent
N/A → 🆕 onTrip(cb) TripEvent (auto-detected trips!)
N/A → 🆕 onRemoteConfig(cb) Config (remote config applied)
removeListeners() → removeListeners() Cancels all subscriptions// Before — so many characters...
bg.BackgroundGeolocation.onLocation((bg.Location location) {
print('[location] $location');
});
// After — ahh, much better
tl.Tracelet.onLocation((tl.Location location) {
print('[location] $location');
});🔧 Métodos: el mapeo completo
Ciclo vital
Before → Tracelet
─────────────────────────────────────────────────────────────
bg.BackgroundGeolocation.ready(cfg) → tl.Tracelet.ready(cfg)
bg.BackgroundGeolocation.start() → tl.Tracelet.start()
bg.BackgroundGeolocation.stop() → tl.Tracelet.stop()
bg.BackgroundGeolocation.startGeofences() → tl.Tracelet.startGeofences()
N/A → 🆕 tl.Tracelet.startPeriodic()
bg.BackgroundGeolocation.getState() → tl.Tracelet.getState()
bg.BackgroundGeolocation.setConfig() → tl.Tracelet.setConfig()
bg.BackgroundGeolocation.reset() → tl.Tracelet.reset()
N/A → 🆕 tl.Tracelet.getHealth()Ubicación
Before → Tracelet
─────────────────────────────────────────────────────────────
getCurrentPosition(...) → getCurrentPosition(...)
same params: desiredAccuracy, timeout,
maximumAge, persist, samples, extras
N/A → 🆕 getLastKnownLocation() — zero battery cost!
watchPosition(cb, ...) → watchPosition(cb, ...) — returns watchId
stopWatchPosition(id) → stopWatchPosition(id)
changePace(isMoving) → changePace(isMoving)
N/A → 🆕 updateLocationProviderOptions() — live
accuracy/filter override, no pipeline restart
getOdometer() → getOdometer()
setOdometer(value) → setOdometer(value)
resetOdometer() → setOdometer(0) — one less method to rememberGeocerca
Before → Tracelet
─────────────────────────────────────────────────────────────
addGeofence(g) → addGeofence(g)
addGeofences(list) → addGeofences(list)
removeGeofence(id) → removeGeofence(id)
removeGeofences() → removeGeofences()
getGeofences() → getGeofences()
N/A → 🆕 getGeofence(id) — get one without fetching all
N/A → 🆕 geofenceExists(id) — quick existence checkPersistencia y sincronización
Before → Tracelet
─────────────────────────────────────────────────────────────
getLocations() → getLocations([SQLQuery?]) — optional filtering!
getCount() → getCount()
destroyLocations() → destroyLocations()
destroyLocation(uuid) → destroyLocation(uuid)
insertLocation(params) → insertLocation(params) — returns UUID
sync() → sync()Permisos: tenemos ayudantes durante días
Before → Tracelet
─────────────────────────────────────────────────────────────
requestPermission() → requestLocationAuthorization()
N/A → 🆕 getLocationAuthorization()
N/A → 🆕 hasBackgroundPermission (getter)
N/A → 🆕 getNotificationAuthorization()
N/A → 🆕 requestNotificationAuthorization()
N/A → 🆕 getMotionAuthorization()
N/A → 🆕 requestMotionAuthorization()
N/A → 🆕 requestTemporaryFullAccuracyAuthorization(purpose) — iOS 14+
N/A → 🆕 canScheduleExactAlarms() — Android 12+
N/A → 🆕 openExactAlarmSettings()
N/A → 🆕 openAppSettings()
N/A → 🆕 openLocationSettings()
N/A → 🆕 openBatterySettings()
N/A → 🆕 isIgnoringBatteryOptimizations()Explotación florestal
Before → Tracelet
─────────────────────────────────────────────────────────────
getLog() → getLog([SQLQuery?]) — optional filtering
destroyLog() → destroyLog()
emailLog(email) → emailLog(email)
log(level, msg) → log(level, msg)Programación, tareas en segundo plano y sin cabeza
Before → Tracelet
─────────────────────────────────────────────────────────────
startSchedule() → startSchedule()
stopSchedule() → stopSchedule()
startBackgroundTask() → startBackgroundTask()
stopBackgroundTask(id) → stopBackgroundTask(id)
registerHeadlessTask(cb) → registerHeadlessTask(cb)Utilidad
Before → Tracelet
─────────────────────────────────────────────────────────────
getProviderState() → getProviderState()
getSensors() → getSensors()
getDeviceInfo() → getDeviceInfo()
playSound(name) → playSound(name)
isPowerSaveMode → isPowerSaveMode
N/A → 🆕 getSettingsHealth() — detects OEM battery killers
N/A → 🆕 openOemSettings(label) — opens OEM settings page
N/A → 🆕 requestSettings(action)
N/A → 🆕 showSettings(action)🔐 Seguimiento de auditoría (solo Tracelet: integridad de nivel empresarial)
verifyAuditTrail(): Verifique la cadena hash SHA-256. ¿Se manipuló algo?getAuditProof(uuid)— Prueba criptográfica para un registro de ubicación específico
🛡️ Zonas de privacidad (solo Tracelet: el RGPD dice gracias)
addPrivacyZone(zone)— Agregar una zona con acción: excluir/degradar/solo eventoaddPrivacyZones(list)— Agregado masivoremovePrivacyZone(id)— Eliminar por identificadorremovePrivacyZones()— Eliminar todogetPrivacyZones()— Listar todas las zonas
🎁 Funciones exclusivas de Tracelet
Funciones que obtienes con Tracelet que no están disponibles en flutter_background_geolocation:
- Modo periódico —
Tracelet.startPeriodic()— Fijación de GPS cada N minutos a través de WorkManager. Sin servicio en primer plano, sin notificación, sin consumo de batería. - Filtro Kalman —
geo.filter.useKalmanFilter: true— EKF de 4 estados suaviza el ruido del GPS. Tus pistas parecen profesionales, no borrachas. - Muestreo adaptativo —
geo.enableAdaptiveMode: true— Ajusta automáticamente el filtro de distancia según la actividad + batería + velocidad. - Detección simulada (3 niveles) —
geo.filter.mockDetectionLevel: detecta la suplantación de GPS mediante el recuento de satélites, la deriva en tiempo real y el análisis de marcas de tiempo. - Zonas de privacidad —
addPrivacyZone()— Excluye, degrada o limita el seguimiento en áreas sensibles. Cumplimiento del RGPD integrado. - Pista de auditoría —
verifyAuditTrail()— Cadena hash SHA-256. Demuestre que sus datos de ubicación no han sido manipulados. - Comprobación de estado —
getHealth()— Una llamada te dice todo: permisos, GPS, batería, problemas OEM, 12 advertencias automáticas. - Compatibilidad OEM —
getSettingsHealth()— Detecta asesinos de batería agresivos en Huawei, Xiaomi, Samsung, OPPO e indica a los usuarios cómo solucionarlos. - Detección de viaje —
onTrip(cb): detecta automáticamente viajes con distancia, duración, puntos de ruta y velocidad promedio. - Geocercas poligonales —
Geofence(vertices: [...])— No solo círculos. Dibuja cualquier forma con soporte poligonal de proyección de rayos. - Eliminación de geocerca —
geofence.geofenceModeKnockOut— La geocerca se elimina automáticamente después de la primera SALIDA. Perfecto para alertas únicas. - Búsqueda de geocercas —
getGeofence(id): consulta una única geocerca sin cargarlas todas. - Ayudantes de permisos:
openAppSettings(),openBatterySettings(): enlaces profundos directos a la configuración del sistema. - Reintentos inteligentes —
http.maxRetries+ retroceso — Retroceso exponencial con fluctuación. Tu servidor te lo agradecerá. - Sincronización solo por Wi-Fi —
http.disableAutoSyncOnCellular: guarda datos móviles, sincroniza solo por Wi-Fi. - Movimiento solo del acelerómetro —
motion.shakeThreshold: detecta movimiento sin permiso de reconocimiento de actividad. Ventana emergente de permiso cero. - Soporte web: la misma API de Dart se ejecuta en el navegador para el seguimiento en primer plano (en pestañas). El seguimiento en segundo plano y varias funciones nativas no están disponibles; consulte Soporte web.
🤷 Funciones que aún no están en Tracelet
Algunas funciones del complemento anterior aún no están disponibles. Están planificados o se solucionan fácilmente:
- Sincronización de geovalla del lado del servidor — Planificada. Por ahora, obtenga desde su API y llame a
addGeofences(). - Interpolación
locationTemplate— Declarado, no cableado. Transforme en devolución de llamadaonLocationo usehttp.extras. - Actualización automática de JWT — Declarado, no cableado. Configure
http.headersmanualmente; escucheonAuthorization. - Servidor de demostración: No planificado. Utilice su propio backend: cualquier punto final REST funciona.
- Activación de clave de licencia — 🎉 ¡No es necesario! Es de código abierto.
🛠️ Migración paso a paso
Paso 1: actualice pubspec.yaml
dependencies:
tracelet: ^3.6.14
Elimine flutter_background_geolocation y cualquier paquete de claves de licencia. ¡Ya no los necesitarás!
Paso 2: configuración de Android
Consulte INSTALL-ANDROID.md . Diferencias clave:
- Dependencias opcionales: 🆕 Tracelet 2.0.0+ requiere que agregues explícitamente
play-services-locationa tubuild.gradlesi deseas un seguimiento GMS de alta precisión. De lo contrario, recurre al GPS AOSP estándar. - Sin clave de licencia: elimina cualquier configuración de
BackgroundGeolocation.orgdeAndroidManifest.xml - Permisos: fusionados automáticamente a través de Gradle, no los declaras
minSdkVersion— API 21+ (igual que antes)- Kotlin: todo el código nativo es Kotlin
Paso 3: configuración de iOS
Consulte INSTALL-IOS.md . Diferencias clave:
- Sin clave de licencia: elimine las entradas plist del complemento anterior
- Modos en segundo plano: lo mismo: actualizaciones de ubicación, búsqueda en segundo plano, notificaciones remotas
Info.plist— mismas claves de descripción de uso (NSLocationAlwaysAndWhenInUseUsageDescription, etc.)Podfile— elimina las fuentes de pods del complemento anterior
Paso 4: actualizar la configuración
Transforma tu piso Config() → compuesto Config(). Consulte la sección Configuración: de plano a estructurado más arriba.
Paso 5: actualizar los oyentes de eventos
Busque y reemplace bg.BackgroundGeolocation.onXxx → tl.Tracelet.onXxx:
// Before
bg.BackgroundGeolocation.onLocation((bg.Location location) {
print('[location] $location');
});
// After
tl.Tracelet.onLocation((tl.Location location) {
print('[location] $location');
});Paso 6: actualizar las llamadas del ciclo de vida
// Before
bg.BackgroundGeolocation.ready(config).then((bg.State state) {
if (!state.enabled) bg.BackgroundGeolocation.start();
});
// After
tl.Tracelet.ready(config).then((tl.State state) {
if (!state.enabled) tl.Tracelet.start();
});Paso 7: actualice la tarea sin cabeza
// Before
@pragma('vm:entry-point')
void backgroundGeolocationHeadlessTask(bg.HeadlessEvent event) async {
switch (event.name) {
case bg.Event.LOCATION:
bg.Location location = event.event;
break;
}
}
void main() {
bg.BackgroundGeolocation.registerHeadlessTask(backgroundGeolocationHeadlessTask);
runApp(MyApp());
}
// After — shorter function name is a bonus 😎
@pragma('vm:entry-point')
void headlessTask(tl.HeadlessEvent event) async {
switch (event.name) {
case 'location':
tl.Location location = event.event as tl.Location;
break;
}
}
void main() {
tl.Tracelet.registerHeadlessTask(headlessTask);
runApp(MyApp());
}📦 Carga útil HTTP: Snake_case → camelCase
¡Atención, desarrolladores backend! Una cosa es actualizar en su servidor.
flutter_background_geolocation envía esto:
{
"location": {
"coords": { "latitude": 37.42, "longitude": -122.08, "accuracy": 12.3 },
"timestamp": "2026-03-06T10:30:00.000Z",
"is_moving": true,
"uuid": "abc-123",
"odometer": 1234.5,
"activity": { "type": "walking", "confidence": 85 },
"battery": { "level": 0.72, "is_charging": false },
"extras": { "custom_key": "custom_value" }
}
}Tracelet envía esto:
{
"location": {
"coords": { "latitude": 37.42, "longitude": -122.08, "accuracy": 12.3 },
"timestamp": "2026-03-06T10:30:00.000Z",
"isMoving": true,
"uuid": "abc-123",
"odometer": 1234.5,
"isMock": false,
"activity": { "type": "walking", "confidence": 85 },
"battery": { "level": 0.72, "isCharging": false },
"extras": { "custom_key": "custom_value" }
}
}TL;DR: is_moving → isMoving, is_charging → isCharging, más un nuevo campo isMock. Actualice su análisis JSON y estará dorado.
🚨 Errores comunes
No los aprenda de la manera más difícil: nosotros ya lo hicimos:
Configahora es compuesto: ajusta los campos enGeoConfig(...),AppConfig(...),HttpConfig(...), etc.desiredAccuracy: -1no funciona — UtiliceDesiredAccuracy.high— enumeraciones escritas, no números mágicoslogLevel: 5no funciona — UtiliceLogLevel.verbose- No puedo encontrar
resetOdometer()— Ahora essetOdometer(0) - La propiedad
notification:desapareció — EsforegroundService: ForegroundServiceConfig(...)dentro deandroid:(AndroidConfig), noapp scheduleUseAlarmManagerno está en AppConfig: ahora esandroid.scheduleUseAlarmManagerpreventSuspendno está en AppConfig: ahora esios.preventSuspend- El backend no puede analizar
is_moving— Ahora esisMoving(camelCase) - ¿Aún tienes el código de clave de licencia? — Elimínalo — Tracelet no lo necesita
- Las propiedades de
Statese ven diferentes: consulte la Referencia de API - Errores de tipo
HeadlessEvent.event— Emitirlo:event.event as tl.Location
📚 Más recursos
- Referencia de API : cada método, cada parámetro
- Guía de configuración : profundiza en todas las opciones de configuración
- Seguimiento en segundo plano : cómo sobrevive a las muertes de la aplicación
- Instalación de Android — Configuración específica de Android
- Instalación de iOS — Configuración específica de iOS
- Problemas de GitHub - ¿Atascado? te tenemos
Bienvenido al lado de código abierto. Tenemos galletas. 🍪