Skip to Content
EmpezandoConfiguración de la plataformaSDK de Android

SDK de Android: Domar el administrador de batería

Android es famoso por eliminar agresivamente los servicios en segundo plano. Los fabricantes de equipos originales chinos (como Xiaomi, Huawei) incluso tienen administradores de energía personalizados que rompen por completo los límites estándar de ejecución en segundo plano de Android.

Esta página explica por qué Android elimina su aplicación y cómo las configuraciones específicas de Android de Tracelet lo resuelven en el mundo real.


Dependencia opcional: ubicación GMS de alta precisión

El SDK de Android de Tracelet puede utilizar Ubicación de servicios de Google PlayFusedLocationProviderClient (mejor precisión y batería), hardware reconocimiento de actividad (caminar / conducir / quieto), y hardware geocercas. Para mantener el SDK liviano y utilizable en dispositivos sin Google, este la dependencia no está incluida. Lo agrega solo si desea la ruta de alta precisión:

// android/app/build.gradle.kts dependencies { implementation("com.google.android.gms:play-services-location:21.3.0") }

Es opcional y el SDK se degrada suavemente. Sin play-services-location, Tracelet recurre al estándar AOSP LocationManager (GPS simple). El seguimiento todavía funciona; solo perderá los beneficios de precisión/batería del proveedor fusionado, el reconocimiento de actividad del hardware y el hardware geocercado. Recomendado: agréguelo a menos que esté dirigido específicamente a dispositivos sin Google/AOSP (por ejemplo, Huawei sin GMS o ROM sin Google).

Versión mínima: 21.2.0. El código de Android de Tracelet llama a la interfaz basada en API FusedLocationProviderClient y ActivityRecognitionClient, que solo se convirtieron interfaces en play-services-location 21.2.0. Las versiones anteriores (por ejemplo, 19.0.0) incluyen estos como clases concretas, por lo que llamar a ellas arroja java.lang.IncompatibleClassChangeError en tiempo de ejecución. Tracelet publica un Gradle restricción de dependencia que eleva play-services-location a 21.2.0+ automáticamente si otra dependencia extrae una versión anterior, pero si fijas la versión tú mismo, mantenla en 21.2.0 o más reciente (recomendamos 21.3.0).

Con play-services-locationSin él (respaldo de AOSP)
Ubicación fusionada (mejor precisión + batería)GPS / red sin procesar a través de LocationManager
Reconocimiento de actividad de hardware (onActivityChange)Detección de movimiento solo con acelerómetro
Geocercas de hardwareEvaluación de geocercas de software (en SDK)

Dependencia opcional: Play Integrity (certificación de dispositivo)

Si utiliza la función certificación de dispositivo de Tracelet (AttestationConfig), Android El lado genera su token criptográfico a través de Google Play Integrity. al igual que play-services-location, esta dependencia no está incluida; la agregas solo cuando habilitar la atestación:

// android/app/build.gradle.kts dependencies { implementation("com.google.android.play:integrity:1.6.0") }

Es opcional y la certificación se degrada gradualmente. Sin Play Integrity dependencia, todo lo demás en Tracelet funciona normalmente; solo la atestación se ve afectada: AttestationConfig(enabled: true) registra una advertencia y Tracelet.getAttestationToken() devuelve null en lugar de un token, en lugar de fallar. Agregue la dependencia solo si habilite la certificación y necesite el veredicto de integridad de Play en Android. Ver el Guía de certificación de dispositivos  para el flujo de trabajo completo y la verificación del lado del servidor.

Debe ser implementation, no compileOnly. Play Integrity es compileOnly en el interior el SDK de Tracelet (por lo que nunca se envía ni se fuerza en aplicaciones que no utilizan la atestación). Si habilita la atestación sin agregar la dependencia a su módulo aplicación como implementation, las clases están ausentes en tiempo de ejecución y la atestación devuelve null de forma silenciosa.


Permisos y configuración de manifiesto

Tracelet inyecta automáticamente los permisos necesarios en su AndroidManifest.xml cuando compila su aplicación. Por defecto solicita:

  • ACCESS_COARSE_LOCATION & ACCESS_FINE_LOCATION (Requerido para seguimiento)
  • ACCESS_BACKGROUND_LOCATION (Requerido para el seguimiento cuando la aplicación está cerrada)
  • FOREGROUND_SERVICE & FOREGROUND_SERVICE_LOCATION (Requerido para ejecución continua en segundo plano)
  • ACTIVITY_RECOGNITION (Requerido para el motor de detección de movimiento inteligente)
  • POST_NOTIFICATIONS (Requerido para la interfaz de usuario del servicio de primer plano de Android 13+)
  • SCHEDULE_EXACT_ALARM (Requerido para un seguimiento preciso del modo periódico)

Eliminación de permisos no utilizados (fusión de manifiesto)

Si su aplicación no necesita una característica específica (por ejemplo, su cliente no necesita detección de movimiento o no usa el modo periódico), puede eliminar el permiso por la fuerza usando la directiva tools:node="remove" de fusión de manifiesto de Android en su nivel de aplicación AndroidManifest.xml (android/app/src/main/AndroidManifest.xml).

El código nativo de Tracelet está completamente protegido con checkSelfPermission(). La falta de permisos provocará retrocesos elegantes, no bloqueos.

PermisoEfecto al eliminarlo (tools:node="remove")
ACTIVITY_RECOGNITIONSeguro. Vuelve a la detección de movimiento básica solo con acelerómetro. La transmisión onActivityChange no se activa (sin clasificación para caminar/correr/conducir).
ACCESS_BACKGROUND_LOCATIONSeguro. Android 10+ restringirá el seguimiento cuando la aplicación esté completamente en segundo plano o se haya eliminado.
SCHEDULE_EXACT_ALARMSeguro. El modo periódico recurre al uso de temporizadores WorkManager que funcionan con batería, pero son inexactos.
POST_NOTIFICATIONSSeguro. La notificación persistente del servicio en primer plano está oculta en Android 13+. El servicio aún funciona.
REQUEST_IGNORE_BATTERY_OPTIMIZATIONSSeguro. No podrás solicitar exenciones de optimización de batería del sistema operativo.
FOREGROUND_SERVICE / FOREGROUND_SERVICE_LOCATIONSeguro para aplicaciones de solo geocerca/solo periódicas. Quitarlas desactiva el seguimiento continuo en primer plano (start()), pero la geocerca estándar y el modo periódico siguen funcionando. Obligatorio para el seguimiento continuo en segundo plano.
ACCESS_FINE_LOCATION / COARSEINSEGURO. Sin ningún permiso de ubicación, Tracelet no puede obtener posiciones.

Política de servicio en primer plano de Google Play (vigente a partir del 28 de octubre de 2026). La geovalla es ya no es un caso de uso permitido para la ubicación del servicio en primer plano. Si su aplicación utiliza un servicio en primer plano únicamente para geocercas, debes eliminar FOREGROUND_SERVICE_LOCATION (y FOREGROUND_SERVICE) de su fusionado manifiesto. El modo de geofence estándar de Tracelet utiliza la API Geofence nativa y no no iniciar un servicio en primer plano, por lo que las aplicaciones que solo utilizan geocercas son compatibles, solo elimine los permisos siguientes y mantenga foregroundService.enabled = false. Ver el Guía de geovallas para más detalles.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- Geofence-only / periodic-only app: no continuous foreground tracking --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" tools:node="remove" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" tools:node="remove" /> </manifest>

Ejemplo: eliminación de permisos de movimiento y fondo

<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <!-- Client doesn't want Activity/Motion tracking --> <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" tools:node="remove" /> <!-- Client only wants foreground tracking --> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" tools:node="remove" /> <!-- Remove Exact Alarms --> <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" tools:node="remove" /> </manifest>

Reglas automáticas de ProGuard / R8

Tracelet utiliza en gran medida servicios Kotlin en segundo plano, enlaces JNA para el núcleo de Rust y canales reflectantes de Pigeon. Si se ofuscan o se reducen incorrectamente, el seguimiento en segundo plano fallará silenciosamente cuando la aplicación se compile para su lanzamiento.

No es necesario configurar manualmente ProGuard para Tracelet.

El complemento tracelet_android se envía automáticamente con consumer-rules.pro integrado. Cuando creas tu aplicación Flutter en modo de lanzamiento, el reductor R8 de Android extrae automáticamente estas reglas y garantiza que todas las clases necesarias (como los enlaces HeadlessTaskService, BootReceiver y Rust uniffi) sobrevivan a la reducción.


Escenario 1: El repartidor (seguimiento continuo)

Conceptos explorados: Modo Doze, Servicios en primer plano, Wakelocks

El problema

Su usuario es un repartidor de pizzas. Se metieron el teléfono en el bolsillo y apagaron la pantalla. Después de 15 minutos, Android ingresa al Modo Doze. Cierra el acceso a la red, pospone trabajos en segundo plano y limita severamente las reactivaciones de la CPU para ahorrar batería. Si su aplicación se basa en un temporizador simple para obtener GPS, Android simplemente se negará a ejecutar el temporizador.

Cómo lo resuelve Tracelet: servicio en primer plano

Un servicio en primer plano le dice a Android: “Oye, estoy haciendo algo increíblemente importante en este momento y el usuario es plenamente consciente de ello. No me mates”.

android: tl.AndroidConfig( foregroundService: tl.ForegroundServiceConfig( enabled: true, channelName: 'Delivery Tracking', notificationText: 'Tracking your route to the customer', notificationOngoing: true, // User cannot swipe it away showNotificationOnPauseOnly: false, // Auto-hides when app is open actions: ['Pause', 'Complete'], // Adds interactive buttons to the notification ), )

Al mostrar una notificación persistente en la barra de estado, Tracelet eleva la prioridad de su aplicación casi al nivel de la interfaz de usuario de primer plano. Android permitirá que Tracelet se ejecute indefinidamente, evitando las restricciones del modo Doze.

Personalizar la apariencia de las notificaciones

Para que la notificación persistente coincida con la marca de tu aplicación, puedes personalizar los íconos y los colores:

android: tl.AndroidConfig( foregroundService: tl.ForegroundServiceConfig( enabled: true, notificationTitle: 'Delivery Mode', notificationText: 'Tracking your route...', notificationColor: '#0F9D58', // Your brand hex color notificationSmallIcon: 'ic_tracelet_icon', // The icon name notificationLargeIcon: 'ic_large_logo', ), )

Reglas de iconos importantes:

  1. Ubicación del archivo: El archivo de imagen debe colocarse en la carpeta dibujable de su proyecto de Android (android/app/src/main/res/drawable/ic_tracelet_icon.png).
  2. Restricciones de íconos pequeños: Android requiere que notificationSmallIcon sea completamente plano, transparente y solo blanco. Si utiliza un logotipo de color, Android simplemente lo representará como un cuadrado gris o blanco sólido.
  3. Propiedad de color: La propiedad notificationColor teñirá el fondo de su pequeño ícono para que coincida con su marca.
🔔

Nota de Android 13+: Debe solicitar el permiso POST_NOTIFICATIONS antes de iniciar el servicio; de lo contrario, el sistema operativo suprimirá silenciosamente la notificación. Consulte la página Flutter SDK: Permisos para saber exactamente cómo solicitar esto desde su código Dart.

Actualizar la notificación durante el seguimiento (updateNotification())

Es necesario cambiar la notificación después de que el seguimiento ya haya comenzado, p. ¿Actualizar el título de “En ruta” a “Llegando”, intercambiar el texto o cambiar los botones de acción a mitad del viaje? Llamar a setConfig() con un nuevo ForegroundServiceConfig mantiene los valores, pero un cambio de solo notificación no vuelve a publicar la notificación que Android ya está mostrando; el nuevo contenido solo aparecería después de un reinicio del servicio no relacionado o una transición en primer plano.

Desde v3.6.8, Tracelet.updateNotification() actualiza la notificación en vivo, sin reiniciar el proceso de seguimiento:

// 1. Apply the new notification content. await Tracelet.setConfig( const tl.Config( android: tl.AndroidConfig( foregroundService: tl.ForegroundServiceConfig( notificationTitle: 'Arriving', notificationText: 'Your driver is 2 minutes away', ), ), ), ); // 2. Repost the active notification with the new content. await Tracelet.updateNotification();

Seguro por diseño. updateNotification() nunca reinicia el seguimiento y no funciona cuando el servicio en primer plano no se está ejecutando actualmente (no hay nada que actualizar). En iOS, actualiza la Actividad en vivo en ejecución (cuando optó por una a través de liveActivityConfig); en la web no es posible, por lo que la misma llamada es segura en todas las plataformas.


Escenario 2: La aplicación meteorológica (seguimiento periódico)

Conceptos explorados: WorkManager frente a Exact Alarms

El problema

Su usuario descargó su aplicación meteorológica local. Desea despertarse en segundo plano una vez cada 4 horas, obtener su ubicación y descargar el pronóstico local.

Usted no desea una notificación persistente del Servicio de primer plano. El usuario odiaría ver una notificación permanente de “Seguimiento del tiempo” en su cajón.

Cómo lo resuelve Tracelet: modo periódico

En lugar de un servicio continuo, Tracelet puede utilizar los programadores de trabajos de Android para despertarse brevemente, obtener una solución y volver a dormir.

android: tl.AndroidConfig( periodicUseForegroundService: false, periodicUseExactAlarms: true, // Uses AlarmManager instead of WorkManager )

Los dos programadores

  1. Administrador de trabajo (periodicUseExactAlarms: false) El valor predeterminado. Es muy amigable con la batería. Sin embargo, Android decide cuándo ejecutarlo. Si le pide que se ejecute cada 15 minutos, Android podría esperar 45 minutos y ejecutarlo cuando el usuario desbloquee su teléfono para consultar Instagram (lo que se denomina “procesamiento por lotes”). Es muy inexacto.

  2. Administrador de alarmas (periodicUseExactAlarms: true) Si es absolutamente NECESARIO activar el dispositivo exactamente a una hora específica, utilice esto. Requiere que declares el permiso SCHEDULE_EXACT_ALARM en tu android/app/src/main/AndroidManifest.xml:

    <uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />

Nota: Google Play revisa estrictamente este permiso. Úselo solo si su aplicación es un despertador, un calendario o si requiere absolutamente una hora exacta.


Escenario 3: La agresión OEM

Conceptos explorados: API de estado de configuración

El problema

Hiciste todo bien. Tienes un servicio en primer plano. Pero el usuario posee un teléfono Xiaomi. MIUI tiene un “Ahorro de batería” patentado que desactiva incluso los servicios en primer plano después de 5 minutos de tiempo de apagado de la pantalla.

Cómo lo resuelve Tracelet: mitigación automática y avisos

Tracelet aplica automáticamente mitigaciones internas siempre que sea posible, pero a veces el usuario tiene que incluir físicamente su aplicación en la lista blanca en el menú de configuración patentado del OEM.

final health = await tl.Tracelet.getSettingsHealth(); if (health['isAggressiveOem'] == true) { // Automatically opens the manufacturer-specific settings screen // (e.g. Xiaomi Autostart, Huawei App Launch, Samsung Sleeping Apps) await tl.Tracelet.showPowerManager(); }

Para ver un ejemplo detallado de cómo implementar esto en su interfaz de usuario de Flutter, consulte la página Herramientas de diagnóstico y administración de energía.