Media3 presenta nuevas optimizaciones, mejoras de comportamiento y mejoras de arquitectura en todas sus bibliotecas. Si bien estos cambios se prueban y verifican de forma exhaustiva antes del lanzamiento, Media3 incluye una infraestructura de marcas de funciones centralizada (androidx.media3.common.Flags) centrada en el modo Canary para que las aplicaciones controlen cómo y cuándo se adoptan los comportamientos nuevos.
En esta página, se explica cómo funcionan el modo Canary y las marcas de funciones, y cómo puedes usarlos en tu aplicación para reducir los riesgos de actualización en las versiones, ejecutar lanzamientos controlados y configurar reversiones de emergencia.
Descripción general
El modo Canary agrupa las mejoras de la biblioteca verificadas y recientemente introducidas en un interruptor global unificado:
- Habilitado de forma predeterminada: En las versiones estándar de Media3, el modo Canary está habilitado de forma predeterminada (
true). Esto garantiza que tu app se beneficie automáticamente de las mejoras de rendimiento, las optimizaciones y las nuevas funciones seguras. - Capacidad de inhabilitación y reversión: Las aplicaciones pueden inhabilitar el modo Canary de forma global o anular marcas de funciones específicas de forma individual en el entorno de ejecución.
- Cero complejidad de cableado: Los parámetros de configuración se administran a través de la clase central
Flagsen el módulocommon, lo que elimina la necesidad de métodos set o de objetos de configuración personalizados en diferentes componentes.
¿Por qué usar marcas en tu app?
Si bien el modo Canary está activo de forma predeterminada, integrar Flags con
la configuración o el framework de experimentación de tu app proporciona varios
beneficios:
1. Mitiga el riesgo de actualización de versión
Actualizar las versiones principales o secundarias de la biblioteca en producción puede generar interacciones inesperadas en dispositivos OEM específicos o canalizaciones de contenido multimedia personalizadas. Cuando actualices Media3, puedes usar el modo Canary y la configuración remota para un flujo de actualización más seguro en todas las versiones:
- Envía la actualización con el modo Canary inhabilitado: El lanzamiento de una nueva versión de Media3 con el modo Canary desactivado conserva, en términos generales, el conjunto de funciones de la versión anterior (con Canary habilitado), lo que te permite verificar la estabilidad de la biblioteca de referencia y las correcciones de errores generales en producción antes de adoptar nuevos comportamientos.
- Habilita el modo canary de forma progresiva: Usa la configuración remota para habilitar el modo canary por etapas en las cohortes de usuarios (por ejemplo, 5% → 25% → 100%) o ejecuta experimentos A/B para medir el impacto de las métricas.
- Revertir si es necesario: Si se produce una regresión en dispositivos específicos, inhabilita de forma remota el modo Canary o el ID de la marca específico sin necesidad de lanzar una app de emergencia.
- Adoptar como predeterminado: Una vez verificado, deja habilitado el modo de versión canary de forma predeterminada hasta la próxima actualización de versión, en la que las funciones de versión canary verificadas anteriormente se vuelven permanentes.
Kotlin
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false)
Java
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false);
2. Lanzamientos en etapas controlados y pruebas A/B
En lugar de exponer al 100% de tus usuarios a los nuevos comportamientos de la biblioteca a la vez, puedes conectar Flags a un sistema de configuración o experimentación remoto.
Puedes habilitar el modo de versiones canary por etapas (por ejemplo, el 5% de los usuarios, el 25% y el 100%) o ejecutar experimentos de pruebas A/B para medir el impacto de las optimizaciones nuevas en las métricas de reproducción principales, como la latencia de inicio, la tasa de almacenamiento en búfer y los errores de reproducción.
3. Interruptor de apagado remoto y reversión rápida
Si se produce una regresión en producción en un modelo de dispositivo o una versión del SO en particular, puedes inhabilitar de forma remota el modo Canary (o el ID de la marca específica responsable) con la configuración del servidor. Esto revierte de inmediato la biblioteca a su comportamiento de resguardo heredado y estable para los usuarios afectados sin necesidad de un hotfix de emergencia de la app ni una versión binaria.
Configura el modo Canary y las marcas
La API de Flags proporciona métodos para controlar el modo de versión canary global y
las anulaciones de marcas individuales.
Modo de versión canary global
Para habilitar o inhabilitar todas las mejoras que abarca el modo Canary, sigue estos pasos:
Kotlin
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false)
Java
// Enable or disable Canary mode globally (defaults to true). Flags.setCanaryModeEnabled(false);
Anula marcas individuales
También puedes habilitar o inhabilitar de forma explícita marcas específicas, independientemente de la configuración global del modo Canary:
Kotlin
// Explicitly enable an experimental flag. Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) // Explicitly disable a flag. Flags.disableFlag(Flags.FLAG_DYNAMIC_SCHEDULING)
Java
// Explicitly enable an experimental flag. Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION); // Explicitly disable a flag. Flags.disableFlag(Flags.FLAG_DYNAMIC_SCHEDULING);
Las anulaciones explícitas siempre tienen prioridad sobre el valor predeterminado global del modo de versión canary.
Verificando el estado de la marca
Para verificar si el modo Canary o una marca específica están activos en tu código, haz lo siguiente:
Kotlin
// Query whether Canary mode is active globally. val isCanaryActive = Flags.isCanaryModeEnabled() // Query whether a specific flag is active. val isFeatureActive = Flags.isEnabled(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION)
Java
// Query whether Canary mode is active globally. boolean isCanaryActive = Flags.isCanaryModeEnabled(); // Query whether a specific flag is active. boolean isFeatureActive = Flags.isEnabled(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION);
Orden de resolución de marcas
Cuando Media3 verifica si una función está habilitada en el entorno de ejecución, resuelve el estado en el siguiente orden:
- Anulación explícita del entorno de ejecución: Si se llamó a
enableFlagodisableFlagpara el ID de la marca, se devuelve ese valor de anulación. - Estado de la biblioteca estática: Si la marca está inhabilitada de forma estática (por ejemplo, una función de desarrollo inicial que aún no está lista para el modo Canary) o habilitada de forma estática (una función que se graduó del modo Canary y que conserva un resguardo de inhabilitación temporal), se devuelve ese valor estático.
- Estado del modo canary: De lo contrario, el parámetro de configuración sigue el modo canary global (habilitado si el modo canary es
true, inhabilitado si esfalse).
Requisitos de inicialización
Configura las marcas antes de crear una instancia de cualquier componente de Media3 (como ExoPlayer, Transformer o MediaSession):
- Configuración anticipada: Configura
Flagsdurante el inicio de la aplicación (por ejemplo, dentro deApplication.onCreate) o antes de inicializar la capa de contenido multimedia de la app. - Seguridad de subprocesos: Los componentes de Media3 leen las marcas durante la creación de instancias y propagan esos valores a los subprocesos internos de reproducción y procesamiento. Asegúrate de que la configuración de la marca se realice antes de crear los componentes de Media3. No se admite modificar marcas mientras los reproductores o transformadores se están ejecutando de forma activa.
Integración con la configuración remota
Una arquitectura recomendada es exponer tres parámetros en tu plataforma de configuración remota:
media3_canary_mode_enabled(booleano): Es el botón de activación global para el modo canary (el valor predeterminado estrue).media3_force_enable_flags(lista de números enteros): Son los IDs de parámetros de configuración específicos que se deben forzar para habilitar las pruebas segmentadas.media3_force_disable_flags(lista de números enteros): IDs de marcas específicos para inhabilitar de forma forzosa si se descubre un problema.
Aplica estos valores durante el inicio antes de crear instancias de reproductor:
Kotlin
fun initializeMedia3Flags( canaryModeEnabled: Boolean, forceEnabledFlags: List<Int>, forceDisabledFlags: List<Int>, ) { // 1. Set global Canary mode state. Flags.setCanaryModeEnabled(canaryModeEnabled) // 2. Apply explicit force-enable overrides. for (flagId in forceEnabledFlags) { Flags.enableFlag(flagId) } // 3. Apply explicit force-disable overrides (remote kill switch). for (flagId in forceDisabledFlags) { Flags.disableFlag(flagId) } }
Java
public static void initializeMedia3Flags( boolean canaryModeEnabled, List<Integer> forceEnabledFlags, List<Integer> forceDisabledFlags) { // 1. Set global Canary mode state. Flags.setCanaryModeEnabled(canaryModeEnabled); // 2. Apply explicit force-enable overrides. for (int flagId : forceEnabledFlags) { Flags.enableFlag(flagId); } // 3. Apply explicit force-disable overrides (remote kill switch). for (int flagId : forceDisabledFlags) { Flags.disableFlag(flagId); } }
Pruebas con marcas
Cuando escribas pruebas de unidades o de Robolectric para instrucciones de código afectadas por marcas de funciones, usa androidx.media3.test.utils.Media3FlagsRule (disponible en el módulo media3-test-utils) para asegurarte de que las pruebas no contaminen el estado estático de las demás.
Limpieza automática con Media3FlagsRule
Agregar Media3FlagsRule garantiza que todas las anulaciones de marcas y las modificaciones del modo Canary se restablezcan automáticamente después de cada prueba:
Kotlin
class MyPlayerTest { @get:Rule val flagsRule = Media3FlagsRule(this) @Test fun playback_withFeatureFlagEnabled() { Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) // Run test with the flag enabled... } }
Java
public static class MyPlayerTest { @Rule public final Media3FlagsRule flagsRule = new Media3FlagsRule(this); @Test public void playback_withFeatureFlagEnabled() { Flags.enableFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION); // Run test with the flag enabled... } }
Pruebas parametrizadas
Puedes combinar Media3FlagsRule con las anotaciones @BindFlag y @BindCanaryMode para ejecutar pruebas parametrizadas en los estados de marcas:
Kotlin
class MyParameterizedPlayerTest { @BindCanaryMode var canaryMode: Boolean = false @BindFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) var perStreamProgression: Boolean = false @get:Rule val flagsRule = Media3FlagsRule(this) @Test fun playback() { // Flags are automatically set for each test parameter combination. } }
Java
public static class MyParameterizedPlayerTest { @BindCanaryMode public boolean canaryMode; @BindFlag(Flags.FLAG_PER_STREAM_MEDIA_PROGRESSION) public boolean perStreamProgression; @Rule public final Media3FlagsRule flagsRule = new Media3FlagsRule(this); @Test public void playback() { // Flags are automatically set for each test parameter combination. } }
Diagnóstico y registro
Media3 proporciona herramientas de diagnóstico para verificar las marcas activas y los estados del modo Canary durante la inicialización de la reproducción y en el entorno de ejecución.
Registros de inicialización
Cuando se inicializa una instancia de ExoPlayer, se imprime el estado activo de Canary
y cualquier anulación explícita en logcat junto con la versión de la biblioteca:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON]
Si las anulaciones están activas, solo se enumeran las desviaciones del estado predeterminado:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON, Overrides: enabled=[1], disabled=[3]]
Inspección programática
Puedes recuperar la cadena de diagnóstico con formato o las listas de anulación de consultas de manera programática (por ejemplo, para incluir el estado de la marca en los informes de fallas o las estadísticas de tu app):
Kotlin
// Get formatted string representing active Canary state and overrides. val flagLogString = Flags.getLogString() // Query explicit override IDs if needed. val enabledFlags = Flags.getEnabledOverrides() val disabledFlags = Flags.getDisabledOverrides()
Java
// Get formatted string representing active Canary state and overrides. String flagLogString = Flags.getLogString(); // Query explicit override IDs if needed. int[] enabledFlags = Flags.getEnabledOverrides(); int[] disabledFlags = Flags.getDisabledOverrides();
Ciclo de vida de los parámetros de configuración
Las marcas en Media3 están diseñadas para ser temporales:
- Desarrollo: Se agrega una optimización o función nueva detrás de un ID de marca en
Flags.java. - Modo Canary: Una vez que se verifica y está lista para el uso general, la función se activa en el modo Canary en todas las versiones.
- Promoción y limpieza: Después de un período de prueba que demuestre la estabilidad en producción, la función se promueve para que se habilite de forma permanente en la biblioteca, y se quitan la constante de la marca, las instrucciones de código de resguardo y las verificaciones condicionales.
Si encuentras un problema con una marca de función, envía un informe en la herramienta de seguimiento de errores de GitHub de AndroidX Media3 para que el equipo pueda solucionarlo antes de la promoción permanente.