Preguntas frecuentes
Permisos generales y bloqueos
¿Qué pasa si no agregamos ningún permiso? ¿Se estrellará?
No, Tracelet no fallará. Tracelet está diseñado para ser altamente resistente. Si intenta llamar a Tracelet.start() sin declarar o solicitar los permisos de ubicación obligatorios, Tracelet detectará correctamente la SecurityException, registrará un error detallado en la consola y emitirá un evento de error a sus oyentes. La aplicación seguirá ejecutándose normalmente. Sin embargo, no se registrarán ubicaciones hasta que se otorguen los permisos.
¿Qué sucede si no habilitamos el permiso de movimiento (actividad física)?
No, no fallará. Si no se concede el permiso ACTIVITY_RECOGNITION (Android) o Motion & Fitness (iOS), Tracelet volverá automáticamente al seguimiento estándar basado en la distancia.
Sin embargo, el consumo de batería aumentará significativamente. Sin detección de movimiento, Tracelet no puede poner el hardware del GPS en modo de suspensión cuando el dispositivo está parado. Se recomienda encarecidamente solicitar este permiso para aplicaciones de producción para garantizar una duración óptima de la batería.
Compilación y configuración de iOS
La compilación de iOS falla con errores de Rust/UniFFI de “símbolo no definido” (_ffi_tracelet_core_rustbuffer_free, _uniffi_tracelet_core_checksum_method_*)
Habilite la integración del Administrador de paquetes Swift de Flutter. El núcleo Rust de Tracelet (TraceletCore.xcframework, que expone los símbolos UniFFI utilizados por tracelet_ios) está vinculado a través del Administrador de paquetes Swift. En la ruta heredada exclusiva de CocoaPods, el marco no está vinculado al objetivo tracelet_ios, por lo que el vinculador de Xcode informa símbolos indefinidos como _ffi_tracelet_core_rustbuffer_free y _uniffi_tracelet_core_checksum_method_*.
Arreglarlo con:
flutter config --enable-swift-package-manager
flutter clean
flutter pub get
flutter run # or: flutter build iosNotas:
- Compile/ejecute desde Flutter CLI o su IDE (Código VS), que impulsa la compilación compatible con SPM, en lugar de abrir
.xcworkspacey compilar directamente desde Xcode. - Esta es una configuración global de Flutter única; no es necesario cambiarlo por proyecto.
flutter clean+ unpod installnuevo por sí solo no lo resolverá: la pieza que falta es SPM que vincula el marco de Rust, no Pods obsoletos.
Batería y sensores de movimiento
¿El sensor de movimiento consume más batería al caminar?
No, en realidad ahorra batería. Los sensores de movimiento de hardware (acelerómetro/detector de pasos) consumen menos de la batería de 0.1% por hora. Tracelet utiliza este sensor de energía ultrabaja para apagar completamente el chip GPS que consume mucha energía (que consume 4-8% por hora) cada vez que el teléfono está apoyado sobre un escritorio.
Cuando empiezas a caminar, el sensor de movimiento activa inmediatamente el GPS para registrar el viaje. El resultado general es un enorme beneficio neto para la duración de la batería en comparación con el seguimiento tradicional.
¿Por qué no recibo actualizaciones continuas cuando el teléfono no se mueve?
Esto es intencional: es el mayor ahorro de batería que ofrece Tracelet. Cuando la detección de movimiento determina que el dispositivo ha estado quieto, Tracelet apaga el GPS continuo y cambia a un modo de bajo consumo (correcciones periódicas de un solo disparo o monitoreo de geovallas). En el momento en que se reanuda el movimiento real, el seguimiento continuo se activa automáticamente.
Si aún desea una ubicación periódica de “Estoy aquí” mientras está parado, configure heartbeatInterval (segundos). Una pequeña desviación del GPS mientras está estacionado no infla el odómetro; las correcciones peores que odometerAccuracyThreshold (50 m predeterminado) están excluidas de la distancia.
¿Cómo puedo reducir aún más el uso de la batería?
Tracelet ya duerme el GPS cuando está parado, pero tienes varias palancas:
- Presupuesto de batería: configure
batteryBudgetPerHourenGeoConfig(por ejemplo,3.0para 3 %/hora). Luego, Tracelet ajusta automáticamentedistanceFilterydesiredAccuracyen tiempo de ejecución para permanecer por debajo de ese objetivo. - Lanzamiento de Wakelock: configura
releaseWakelockWhenStationary: trueenAndroidConfigpara permitir que la CPU entre en modo de suspensión total cuando el usuario está estacionario (requiereMotionDetectionMode.smart). - Filtro de distancia: un
distanceFilter(metros) más grande registra menos correcciones mientras se mueve. - Menor precisión:
desiredAccuracydemedium/lowconsume menos energía quehigh/best. - Modo periódico: para casos de uso de “dónde están aproximadamente”, las correcciones periódicas únicas (
startPeriodic) son considerablemente más económicas que el seguimiento continuo. - Mantener el permiso de movimiento concedido: sin
ACTIVITY_RECOGNITIONTracelet no puede desactivar el GPS de forma tan agresiva.
¿Cuál es la diferencia entre las opciones motionDetectionMode?
motionDetectionMode decide cómo Tracelet detecta el movimiento para iniciar/detener el GPS:
accelerometer: utiliza los sensores de movimiento del hardware (y el reconocimiento de actividad cuando esté permitido). Mínima potencia, funciona en interiores y sin conexión GPS.speed: utiliza únicamente la velocidad del GPS. Simple y predecible, pero necesita una posición de GPS para notar que te has detenido, por lo que reacciona más lento y usa más energía.smart— combina ambos: permanece en seguimiento continuo si ya sea el acelerómetro o la velocidad del GPS indican que te estás moviendo, y solo se detiene cuando ambos coinciden en que te has detenido. Más robusto contra transiciones falsas; Recomendado para la mayoría de las aplicaciones.
Servicios de ubicación y estados de seguimiento
¿Qué sucede si el usuario desactiva los servicios de ubicación mientras el seguimiento está activo?
Respuesta corta: Tracelet no detiene, bloquea ni derriba el seguimiento. Mantiene activada la sesión de seguimiento, emite un evento providerchange para que su aplicación pueda reaccionar, no registra ubicaciones nuevas mientras la ubicación está desactivada (con dos excepciones específicas de la plataforma a continuación) y reanuda automáticamente la entrega de ubicaciones en el momento en que el usuario vuelve a habilitar la ubicación, en todos los estados (en primer plano, en segundo plano, finalizado). No es necesario que vuelvas a llamar a start().
“Servicios de ubicación desactivados” aquí significa el cambio de ubicación a nivel del sistema operativo (Android: Configuración → Ubicación; iOS: Configuración → Privacidad → Servicios de ubicación). Revocar el permiso de la aplicación es un caso relacionado pero separado; consulte la nota al final de esta respuesta.
como detectarlo
final sub = tl.Tracelet.onProviderChange((tl.ProviderChangeEvent e) {
if (!e.enabled) {
// Location services were turned OFF — prompt the user / show a banner.
} else {
// Back ON — Tracelet has already resumed; no action required.
}
});ProviderChangeEvent transporta enabled, status (autorización), gps, network, accuracyAuthorization, gpsFallback y mockLocationsDetected. El mismo evento se entrega a la devolución de llamada sin cabeza en el estado de fondo/inactivo (si está registrado) y se conserva como un registro providerchange a menos que configure disableProviderChangeRecord: true.
Comportamiento por estado y plataforma
| Estado | Androide | iOS |
|---|---|---|
| Primer plano | incendios providerchange (enabled: false); el servicio de primer plano permanece vivo; no hay nuevas correcciones hasta que se vuelva a habilitar. | providerchange incendios; didFailWithError se maneja con elegancia (los one-shots retroceden a la última ubicación conocida); no hay nuevas correcciones. |
| Fondo | El servicio en primer plano (y su notificación) sigue ejecutándose; las actualizaciones fusionadas simplemente se detienen; providerchange aún enviado. Se reanuda al volver a habilitar. | La suscripción CLLocationManager permanece registrada; iOS no entrega nada hasta que la ubicación regresa, luego se reanuda (y puede reiniciar la aplicación a través de la región/SLC). |
| Terminado (muerto) | Si una sesión en segundo plano/arranque está activa (stopOnTerminate: false / startOnBoot), el servicio se comporta como En segundo plano arriba. Si el proceso no está activo, no se ejecuta nada hasta que el sistema operativo lo inicie nuevamente. | iOS reinicia la aplicación a través del monitoreo de ubicación/región importante solo cuando ocurre un evento de ubicación/región, lo cual no puede hacer mientras la ubicación está desactivada. Una vez que se vuelva a habilitar, el siguiente evento de clasificación se reinicia y se reanuda. |
En todos los casos, el estado de la sesión se conserva, por lo que al volver a habilitar la ubicación se reanuda el seguimiento automáticamente sin reinicialización.
Lo que Tracelet no hace
- No detiene automáticamente la sesión ni borra su configuración/estado.
- No se lanza ni se bloquea: se detecta el error de “ubicación desactivada/denegada” de la plataforma.
- No fabrica ubicaciones (excepto la navegación a estima de Android, a continuación): su base de datos simplemente tiene un espacio durante el período en que la ubicación estuvo desactivada.
Detalles específicos de la plataforma que vale la pena conocer
Android: si el usuario desactiva GPS pero el posicionamiento Wi-Fi/celular aún está activado, Tracelet automáticamente vuelve al posicionamiento de potencia equilibrada y emite providerchange con gpsFallback: true, restaurando la precisión total cuando regresa el GPS. Esas correcciones aproximadas son grabadas y sincronizadas (etiquetadas con locationSource y su accuracy real). Si enableDeadReckoning: true, después de perder el GPS durante el retraso configurado, Tracelet estima las posiciones de los sensores de movimiento hasta que regresa una solución real. La notificación persistente permanece visible en todo momento.
iOS: un requestLocation() fallido resuelve solicitudes únicas con la última ubicación conocida en lugar de colgarse. iOS no ofrece eventos en segundo plano ni de reinicio mientras la ubicación está desactivada; la entrega y el relanzamiento del estado eliminado se reanudan una vez que se vuelve a encender.
Qué debes hacer en tu aplicación
- Suscríbase a
onProviderChangey muestre un banner/diálogo cuandoenabled == false. - Opcionalmente, guíe al usuario a la configuración a través de
Tracelet.openLocationSettings(). - No llame nuevamente a
start()al volver a habilitarlo: Tracelet se reanuda por sí solo; llamar astart()es inofensivo pero innecesario.
Revocar el permiso de la aplicación versus desactivar la opción
Desactivar alternar afecta a todas las aplicaciones y es completamente recuperable como se indicó anteriormente. La revocación del permiso de ubicación de la aplicación (o la degradación de “Siempre” → “Mientras está en uso”) se informa a través del mismo evento providerchange a través de los campos status / accuracyAuthorization. En Android 12+, si se pierde el permiso de ubicación en segundo plano, se omite intencionalmente un inicio/reinicio en segundo plano (de lo contrario, fallaría silenciosamente): vuelva a otorgar el permiso y reinicie para reanudar.
¿Qué tan precisas son las ubicaciones y cómo distingo el GPS de las conexiones Wi-Fi/celular?
Cada Location lleva un coords.accuracy real en metros y una etiqueta locationSource: "gps" (≤50 m), "wifi" (≤200 m), "cell" (peor) o "network" (durante el respaldo del GPS). Tracelet no deja caer silenciosamente correcciones de baja precisión (las registra para que su recorrido se mantenga continuo), pero mantiene las correcciones deficientes fuera del odómetro (odometerAccuracyThreshold, 50 m predeterminado) y rechaza saltos de velocidad imposible (maxImpliedSpeed).
Si solo desea datos con calidad GPS, filtre por locationSource == "gps" o accuracy <= 50. Si el usuario solo otorgó una ubicación aproximada/aproximada (o iOS “Preciso: Desactivado”), cada corrección es aproximada según la política del sistema operativo; verifique accuracyAuthorization / reducedAccuracy.
¿Por qué getCurrentPosition() falla con LOCATION_FAILURE en algunos teléfonos pero funciona en otros?
PlatformException(LOCATION_FAILURE, "Failed to obtain location") significa que la solicitud única no pudo obtener una nueva solución dentro de timeout y no tenía una ubicación en caché a la cual recurrir. No es un error en su código: es que el GPS/pila fusionada del dispositivo no logra entregar una solución a tiempo. Un one-shot de alta precisión solicita una solución nueva, y si eso se logra dentro de (por ejemplo) 30 s depende en gran medida del dispositivo y el entorno:
- “Precisión de ubicación de Google” está desactivada — Configuración → Ubicación → Servicios de ubicación → Precisión de ubicación de Google (escaneo de Wi-Fi/Bluetooth). Cuando está activado, el proveedor fusionado devuelve una conexión de Wi-Fi/celular en el interior casi al instante; cuando está apagado, el teléfono debe esperar una señal de GPS sin procesar que nunca llega al interior. Esta es la causa número uno de “funciona en mi teléfono, no en el de ellos”.
- Interiores / subterráneos / sin vista del cielo: una localización GPS en frío necesita visibilidad del cielo, y los conjuntos de chips económicos pueden exceder los 30 s para una primera localización en frío (TTFF), mientras que los buques insignia obtienen localizaciones de GPS asistido en segundos.
- Proveedor de GPS deshabilitado a nivel del sistema operativo (ubicación solo de red): una solicitud pura de alta precisión no tiene nada que bloquear.
- Servicios de Google Play faltantes/obsoletos (algunas compilaciones de Huawei/AOSP): el cliente fusionado no se puede ejecutar.
- Recuento de muestras: con
samples: 3Tracelet debe recopilar tres correcciones; en señal marginal puede obtener uno y expirar antes que el resto.samples: 1es más tolerante en interiores.
Cómo hacerlo confiable: recurra a la última ubicación conocida:
Future<tl.Location?> bestPosition() async {
try {
return await tl.Tracelet.getCurrentPosition(
desiredAccuracy: tl.DesiredAccuracy.high,
timeout: 60, // cold GPS fixes on budget phones can exceed 30 s
samples: 1, // more forgiving indoors than 3
maximumAge: 30000, // accept a <30 s-old cached fix instantly
);
} on PlatformException catch (e) {
if (e.code == 'LOCATION_FAILURE') {
// Weak/indoor signal — fall back to the cached fix before giving up.
return await tl.Tracelet.getLastKnownLocation();
}
rethrow;
}
}maximumAgedevuelve una corrección reciente en caché inmediatamente sin activar el GPS, ideal para asistencia/registro donde una posición de 30 s de antigüedad está bien.getLastKnownLocation()nunca activa un proveedor y devuelve lo que contiene el caché fusionado, por lo que solo muestra un mensaje de “señal débil” cuando realmente no hay nada disponible.- Mantenga
timeoutgeneroso (45–60 s) para la primera corrección después del lanzamiento y solicite a los usuarios que habiliten Precisión de ubicación de Google si las correcciones internas siguen fallando (detecta el estado del proveedor a través degetProviderState()/getHealth()).
Antecedentes y terminación
¿Tracelet sigue rastreando después de cerrar o borrar la aplicación?
Android: sí, con stopOnTerminate: false. Cuando el usuario elimina la aplicación de las recientes, Tracelet transfiere el seguimiento a un servicio nativo en segundo plano que no necesita motor Flutter, por lo que la captura y sincronización de la ubicación continúan. La notificación persistente del servicio en primer plano es lo que mantiene vivo ese servicio. Con stopOnTerminate: true, el seguimiento se detiene al deslizar el dedo como se esperaba.
iOS: depende de cómo se cerró la aplicación. Si iOS finaliza la aplicación por motivos de memoria/sistema, la reinicia en segundo plano en el siguiente cambio significativo de ubicación y la reanuda. Si el usuario fuerza el cierre de la aplicación (deslice el dedo hacia arriba en el selector de aplicaciones), iOS suspende deliberadamente todos sus servicios de ubicación hasta que la aplicación se abre nuevamente; Apple no permite que ningún SDK anule esto.
Sin conexión y sincronización
¿Qué pasa con mis ubicaciones si el dispositivo no tiene internet?
No se pierde nada. Cada corrección se escribe en la base de datos del dispositivo (cifrada cuando encryptDatabase: true) en el instante en que se captura, independientemente de la red. La sincronización automática los carga cuando vuelve la conectividad, reintentando con un retroceso exponencial (maxRetries, retryBackoffBase, retryBackoffCap). Un lote se elimina de la base de datos solo después de que el servidor confirma la recepción, por lo que una carga fallida o interrumpida simplemente se reintenta, nunca se descarta.
Las ubicaciones se encuentran dentro de sus límites de retención (maxDaysToPersist, maxRecordsToPersist); los más viejos se podan una vez superados estos. También puedes retener cargas desde el celular con disableAutoSyncOnCellular: true.
¿Tracelet_sync se enviará automáticamente a mi backend cuando vuelva Internet?
Sí, automáticamente y completamente en segundo plano. Si usa tracelet_sync (o sus contenedores como tracelet_supabase / tracelet_firebase), no necesita escribir ninguna lógica de reintento de red usted mismo.
Cuando el sistema operativo detecta que se ha restaurado la conectividad de la red, el motor de sincronización nativo se activa inmediatamente en segundo plano y comienza a cargar las ubicaciones almacenadas en caché en su servidor en lotes cronológicos. Continúa cargándose hasta que la base de datos local esté completamente al día con el servidor, lo que garantiza cero pérdida de datos incluso después de períodos prolongados sin conexión.
Reiniciar y desbloquear dispositivo
Después de reiniciar, ¿Tracelet comienza a rastrear antes de que desbloquee el dispositivo?
No: el dispositivo debe desbloquearse al menos una vez después de reiniciar antes de que se reanude Tracelet. Esta es una regla de la plataforma Android (arranque directo/cifrado basado en archivos), no una limitación de Tracelet, y se aplica a cada SDK de ubicación.
Después de un arranque en frío, el dispositivo está en modo Arranque directo y la mayoría de los datos de la aplicación aún están cifrados. Android solo ofrece la transmisión BOOT_COMPLETED que escucha el receptor de arranque de Tracelet después de que el usuario desbloquea el dispositivo por primera vez (PIN/patrón/contraseña/biométrico). Hasta entonces, el almacenamiento cifrado de credenciales que contiene la base de datos de configuración, estado y ubicación de Tracelet es inaccesible: no hay nada que leer ni escribir.
Por lo tanto, la secuencia después de un reinicio es:
- El dispositivo arranca → Tracelet está inactivo.
- El usuario se desbloquea una vez →
BOOT_COMPLETEDse activa → Tracelet reanuda el seguimiento y la sincronización.
Sólo importa el primer desbloqueo. Después de eso, la pantalla se puede bloquear nuevamente (teléfono en el bolsillo, pantalla apagada) y el seguimiento/sincronización continúa normalmente.
Requisitos para reanudar el arranque: startOnBoot: true, stopOnTerminate: false y permiso de ubicación en segundo plano (“Siempre”) concedidos. En Android 14+, el sistema operativo además prohíbe iniciar un servicio en primer plano de ubicación desde el inicio, por lo que Tracelet recurre a WorkManager/seguimiento de alarmas (sin notificación persistente) hasta que se abre la aplicación la próxima vez.
iOS no puede iniciarse automáticamente al reiniciar: las aplicaciones no pueden ejecutarse al iniciarse y permanecer sin iniciarse hasta que el usuario abra la aplicación o un cambio significativo de ubicación la reinicie, lo que a su vez solo ocurre después del primer desbloqueo posterior al reinicio.
¿Puede realizar un seguimiento antes del primer desbloqueo?
No por defecto. Capturar ubicaciones antes del desbloqueo requiere un arranque directo de Android, lo que significa mover los datos que Tracelet necesita a un almacenamiento cifrado por dispositivo, legible antes de que el usuario se autentique, una garantía en reposo más débil que el almacenamiento cifrado con credenciales (y opcionalmente protegido con encryptDatabase) que Tracelet usa normalmente. Para mantener sus datos completamente protegidos, Tracelet no habilita el arranque directo de fábrica. Si el seguimiento previo al desbloqueo es un requisito estricto para su caso de uso, se puede habilitar como una opción avanzada a nivel de aplicación; comuníquese con nosotros antes de confiar en él.
Geocerca
Las transiciones de geocerca no se activan cuando pruebo con ubicaciones simuladas/simuladas (funcionó en 1.x)
Las ubicaciones simuladas aún funcionan, pero en el modo de geocerca de alta precisión, las correcciones simuladas se filtran antes de que se evalúe la geocerca. Con geofenceModeHighAccuracy: true, las transiciones se calculan en la aplicación a partir del flujo continuo de GPS y el evaluador solo ejecuta las correcciones que pasan el filtro de ubicación. Las herramientas de simulación de rutas suelen “teletransportarse” entre puntos y esos saltos son rechazados por:
maxImpliedSpeed: la velocidad inverosímil entre dos muestras muy alejadas se trata como un valor atípico y se elimina.useKalmanFilter: true: las peleas más suaves luchan contra saltos simulados abruptos y no físicos.trackingAccuracyThreshold: algunos proveedores simulados informanaccuracy = 0o un valor poco realista que no supera el umbral.
Una geocerca colocada en su ubicación actual aún se activa porque geofenceInitialTriggerEntry: true emite un ENTER al registrarse (no se necesita movimiento), por lo que nunca pasa por el filtro.
Para pruebas simuladas en modo de alta precisión, relaje los filtros:
filter: tl.LocationFilter(
rejectMockLocations: false,
useKalmanFilter: false, // disable smoothing
maxImpliedSpeed: 0, // 0 disables the implied-speed reject
trackingAccuracyThreshold: 0, // accept regardless of reported accuracy
),
geo: tl.GeoConfig(distanceFilter: 0, disableElasticity: true),Seleccione también su aplicación simulada en Opciones de desarrollador → Seleccionar aplicación de ubicación simulada y avance por la ruta simulada en pasos pequeños y realistas.
La ruta más sencilla es realizar la prueba en el modo de geocerca estándar (geofenceModeHighAccuracy: false), que delega al servicio de geocerca del sistema operativo. El sistema operativo evalúa el proveedor fusionado y respeta la aplicación de ubicación simulada del sistema sin los filtros SDK; use un radio de ≥ ~100 m allí, ya que el sistema operativo impone un mínimo práctico y las transiciones pequeñas/SALIDA no son confiables por debajo de eso.
Con debug: true y logLevel: verbose, observe los registros de Location filtered by Rust processor: <reason>: le indica exactamente qué filtro eliminó cada solución simulada.
Seguridad y privacidad de los datos
¿Mis datos de ubicación están cifrados en reposo?
Opcionalmente si. Configure encryptDatabase: true para cifrar la base de datos SQLite local que almacena las ubicaciones. En Android, esto usa SQLCipher (AES-256) y requiere que agregues la dependencia de SQLCipher a tu aplicación; se mantiene opcional, por lo que la compilación predeterminada permanece pequeña y llamar a encryptDatabase sin ella genera un error claro. En iOS, el almacén cifrado se gestiona de forma nativa.
Para evidencia de manipulación en lugar de confidencialidad, el pista de auditoría (audit.enabled) encadena cada registro (por ejemplo, SHA-256) para que pueda demostrar que el historial no se modificó después del hecho. Zonas de privacidad te permiten suprimir o redactar correcciones dentro de áreas sensibles (como la casa de un usuario).
¿Tracelet detecta ubicaciones GPS simuladas o falsas?
Sí, a través de mockDetectionLevel en LocationFilter:
disabled(predeterminado): todas las ubicaciones se aceptan incondicionalmente.basic: confía en el indicador “es simulado” de la plataforma.heuristic: la bandera de la plataforma más heurísticas nativas y una verificación de marca de tiempo del lado de Dart, para detectar falsificadores que ocultan la bandera.
En heuristic, cada Location está anotado con el motivo por el que se consideró real o falso, por lo que puede aceptar, marcar o rechazar correcciones simuladas en su propia lógica.
Migrando desde flutter_background_geolocation
Vengo de flutter_background_geolocation. ¿Qué tan difícil es el cambio?
La API de Tracelet está intencionalmente cerca de flutter_background_geolocation, por lo que la mayoría de las aplicaciones se asignan con cambios mínimos: ready/start/stop, los eventos de ubicación/movimiento/proveedor y la sincronización HTTP tienen equivalentes directos. Consulte la guía de migración completa para ver la tabla de configuración/mapeo de eventos y algunas diferencias de comportamiento a tener en cuenta.