O Media3 apresenta novas otimizações, melhorias de comportamento e melhorias de arquitetura
em todas as bibliotecas. Embora essas mudanças sejam testadas e
verificadas minuciosamente antes do lançamento, o Media3 inclui uma infraestrutura centralizada de flags de recursos (androidx.media3.common.Flags) centrada no modo canário
para que os aplicativos controlem como e quando novos comportamentos são adotados.
Nesta página, explicamos como o modo canário e as flags de recurso funcionam e como usá-los no aplicativo para reduzir os riscos de upgrade entre as versões, executar implantações controladas e configurar reversões de emergência.
Visão geral
O modo canário agrupa as melhorias de biblioteca recém-introduzidas e verificadas em um botão global unificado:
- Ativado por padrão: nas versões padrão do Media3, o modo Canary é ativado
por padrão (
true). Isso garante que seu app se beneficie automaticamente de melhorias de desempenho, otimizações e novos recursos seguros. - Capacidade de desativação e reversão: os aplicativos podem desativar o modo canário globalmente ou substituir flags de recursos específicas individualmente no ambiente de execução.
- Zero complexidade de fiação: as flags são gerenciadas pela classe central
Flagsno módulocommon, eliminando a necessidade de setters personalizados ou objetos de configuração em diferentes componentes.
Por que usar sinalizações no app?
Embora o modo canário esteja ativo por padrão, integrar o Flags à
configuração ou ao framework de experimentos do app oferece vários
benefícios:
1. Como reduzir o risco de upgrade de versão
O upgrade de versões principais ou secundárias da biblioteca na produção pode introduzir interações inesperadas em dispositivos OEM específicos ou pipelines de mídia personalizados. Ao atualizar o Media3, use o modo canário e a configuração remota para um fluxo de upgrade mais seguro entre as versões:
- Envie a atualização com o modo canário desativado: o lançamento de uma nova versão do Media3 com o modo canário desativado preserva o conjunto de atributos da versão anterior (com o modo canário ativado), permitindo que você verifique a estabilidade da biblioteca de referência e as correções de bugs gerais na produção antes de adotar novos comportamentos.
- Ativar o modo canário progressivamente: use a configuração remota para ativar o modo canário em etapas em coortes de usuários (por exemplo, 5% → 25% → 100%) ou execute experimentos A/B para medir o impacto das métricas.
- Reverter se necessário: se ocorrer uma regressão em dispositivos específicos, desative remotamente o modo canário ou o ID de flag específico sem precisar de uma versão de emergência do app.
- Adotar como padrão: depois de verificado, deixe o modo canário ativado por padrão até o próximo upgrade de versão, em que os recursos canário verificados anteriormente se tornam 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. Lançamentos graduais controlados e testes A/B
Em vez de expor 100% dos usuários aos novos comportamentos da biblioteca de uma só vez, você
pode conectar Flags a uma configuração remota ou a um sistema de
experimentos.
É possível ativar o modo canário em etapas (por exemplo, 5% dos usuários → 25% → 100%) ou realizar experimentos A/B para medir o impacto de novas otimizações nas principais métricas de reprodução, como latência de inicialização, taxa de armazenamento em buffer e falhas de reprodução.
3. Interruptor de emergência remoto e reversão rápida
Se ocorrer uma regressão na produção em um modelo de dispositivo ou versão do SO específico, você poderá desativar remotamente o modo canário (ou o ID da flag responsável) usando a configuração do lado do servidor. Isso reverte imediatamente a biblioteca para o comportamento de fallback estável e legado para os usuários afetados, sem exigir um hotfix de emergência do app ou uma versão binária.
Como configurar o modo canário e as flags
A API Flags oferece métodos para controlar o modo canário global e
as substituições de flags individuais.
Modo canário global
Para ativar ou desativar todas as melhorias cobertas pelo modo canário:
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);
Como substituir flags individuais
Também é possível ativar ou desativar explicitamente flags específicas, independentemente da configuração global do 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);
As substituições explícitas sempre têm precedência sobre o padrão global do modo canário.
Verificar o status da sinalização
Para verificar se o modo canário ou uma flag específica está ativa no seu código:
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);
Ordem de resolução de flags
Quando o Media3 verifica se um recurso está ativado no momento da execução, ele resolve o estado na seguinte ordem:
- Substituição explícita do ambiente de execução: se
enableFlagoudisableFlagtiver sido chamado para o ID da flag, o valor de substituição será retornado. - Estado da biblioteca estática: se a flag estiver desativada estaticamente (por exemplo, um recurso de desenvolvimento inicial que ainda não está pronto para o modo canário) ou ativada estaticamente (um recurso que saiu do modo canário e manteve um substituto temporário de desativação), esse valor estático será retornado.
- Estado do modo canário: caso contrário, a flag segue a configuração global do modo canário (ativada se o modo canário for
true, desativada se forfalse).
Requisitos de inicialização
Configure as flags antes de instanciar qualquer componente do Media3, como
ExoPlayer, Transformer ou MediaSession:
- Configuração antecipada: configure o
Flagsdurante a inicialização do aplicativo (por exemplo, emApplication.onCreate) ou antes de inicializar a camada de mídia do app. - Concorrência segura: os componentes do Media3 leem flags durante a instanciação e propagam esses valores para as linhas de execução internas de reprodução e processamento. Verifique se a configuração da flag ocorre antes de criar componentes do Media3. Não é possível modificar as flags enquanto os players ou transformadores estão em execução.
Como fazer a integração com a configuração remota
Uma arquitetura recomendada é expor três parâmetros na plataforma de configuração remota:
media3_canary_mode_enabled(booleano): alternância global para o modo canário (o padrão étrue).media3_force_enable_flags(lista de números inteiros): IDs de sinalização específicos para forçar a ativação de testes segmentados.media3_force_disable_flags(lista de números inteiros): IDs de sinalizações específicas para desativar se um problema for descoberto.
Aplique esses valores durante a inicialização antes de criar instâncias do player:
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); } }
Como testar com flags
Ao escrever testes de unidade ou do Robolectric para caminhos de código afetados por flags de
recurso, use androidx.media3.test.utils.Media3FlagsRule (disponível no
módulo media3-test-utils) para garantir que os testes não poluam o estado estático
uns dos outros.
Limpeza automática com Media3FlagsRule
Adicionar Media3FlagsRule garante que todas as substituições de flag e modificações do modo Canary
sejam redefinidas automaticamente após cada teste:
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... } }
Teste parametrizado
É possível combinar Media3FlagsRule com as anotações @BindFlag e @BindCanaryMode
para executar testes parametrizados em estados de flag:
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 e geração de registros
O Media3 oferece ferramentas de diagnóstico para verificar as flags ativas e os estados do modo Canary durante a inicialização da reprodução e no momento da execução.
Registros de inicialização
Quando uma instância ExoPlayer é inicializada, ela mostra o estado ativo do Canary
e as substituições explícitas no logcat, além da versão da biblioteca:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON]
Se as substituições estiverem ativas, somente os desvios do estado padrão serão listados:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON, Overrides: enabled=[1], disabled=[3]]
Inspeção programática
É possível recuperar a string de diagnóstico formatada ou as listas de substituição de consulta de forma programática (por exemplo, para incluir o estado da flag nos relatórios de falhas ou análises do 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 da sinalização
As flags no Media3 são projetadas para serem temporárias:
- Desenvolvimento: uma nova otimização ou recurso é adicionado por trás de um ID de flag em
Flags.java. - Modo canário: depois de verificado e pronto para uso geral, o recurso é ativado no modo canário em todas as versões.
- Promoção e limpeza: após um período de teste que comprove a estabilidade na produção, o recurso é promovido para ativação permanente na biblioteca, e a constante de flag, os caminhos de código substitutos e as verificações condicionais são removidos.
Se você encontrar um problema com uma flag de recurso, registre um relatório no Issue Tracker do GitHub do Media3 do AndroidX para que a equipe possa resolvê-lo antes da promoção permanente.