Media3 bietet neue Optimierungen, Verhaltensverbesserungen und Architekturverbesserungen in allen Bibliotheken. Diese Änderungen werden vor der Veröffentlichung gründlich getestet und überprüft. Media3 enthält jedoch eine zentrale Infrastruktur für Funktions-Flags (androidx.media3.common.Flags), die sich auf den Canary-Modus konzentriert. So können Anwendungen steuern, wie und wann neue Verhaltensweisen übernommen werden.
Auf dieser Seite wird erläutert, wie der Canary-Modus und Funktions-Flags funktionieren und wie Sie sie in Ihrer Anwendung verwenden können, um Upgraderisiken bei Releases zu reduzieren, kontrollierte Roll-outs auszuführen und Notfall-Rollbacks zu konfigurieren.
Übersicht
Im Canary-Modus werden neu eingeführte, verifizierte Bibliotheksverbesserungen unter einer einheitlichen, globalen Ein/Aus-Schaltfläche zusammengefasst:
- Standardmäßig aktiviert: In Standard-Media3-Releases ist der Canary-Modus standardmäßig aktiviert (
true). So profitiert Ihre App automatisch von sicheren Leistungsverbesserungen, Optimierungen und neuen Funktionen. - Deaktivierung und Rollback: Anwendungen können den Canary-Modus global deaktivieren oder bestimmte Funktions-Flags zur Laufzeit einzeln überschreiben.
- Keine komplexe Verkabelung: Flags werden über die zentrale Klasse
Flagsim Modulcommonverwaltet. Dadurch sind keine benutzerdefinierten Setter oder Konfigurationsobjekte für verschiedene Komponenten erforderlich.
Warum sollten Sie Flags in Ihrer App verwenden?
Der Canary-Modus ist standardmäßig aktiviert. Die Einbindung von Flags in die Konfiguration oder das Experimentier-Framework Ihrer App bietet jedoch mehrere Vorteile:
1. Risiko von Versionsupgrades minimieren
Das Upgrade von Haupt- oder Nebenversionen der Bibliothek in der Produktion kann zu unerwarteten Interaktionen auf bestimmten OEM-Geräten oder benutzerdefinierten Medienpipelines führen. Wenn Sie Media3 aktualisieren, können Sie den Canary-Modus und die Remote-Konfiguration für einen sichereren Upgrade-Ablauf über Releases hinweg verwenden:
- Update mit deaktiviertem Canary-Modus veröffentlichen: Wenn Sie eine neue Media3-Version mit deaktiviertem Canary-Modus veröffentlichen, bleibt der Funktionsumfang der vorherigen Version (mit aktiviertem Canary-Modus) weitgehend erhalten. So können Sie die grundlegende Stabilität der Bibliothek und allgemeine Fehlerkorrekturen in der Produktion überprüfen, bevor Sie neue Verhaltensweisen übernehmen.
- Canary-Modus schrittweise aktivieren: Verwenden Sie die Remote-Konfiguration, um den Canary-Modus schrittweise für Nutzerkohorten zu aktivieren (z. B. 5 % → 25 % → 100 %) oder führen Sie A/B-Tests durch, um die Auswirkungen auf die Messwerte zu messen.
- Bei Bedarf zurücksetzen: Wenn auf bestimmten Geräten eine Regression auftritt, können Sie den Canary-Modus oder die entsprechende Flag-ID per Remotezugriff deaktivieren, ohne dass eine Notfallversion der App erforderlich ist.
- Als Standard übernehmen: Lassen Sie den Canary-Modus nach der Überprüfung standardmäßig aktiviert, bis das nächste Versionsupgrade erfolgt. Dann werden die zuvor überprüften Canary-Funktionen dauerhaft übernommen.
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. Kontrollierte gestaffelte Releases und A/B-Tests
Anstatt 100 % Ihrer Nutzer auf einmal mit neuen Bibliotheksverhalten zu konfrontieren, können Sie Flags mit einem Remote-Konfigurations- oder Experimentiersystem verbinden.
Du kannst den Canary-Modus schrittweise aktivieren (z. B. 5 % der Nutzer → 25 % → 100 %) oder A/B-Tests durchführen, um die Auswirkungen neuer Optimierungen auf wichtige Wiedergabemesswerte wie Startlatenz, Rebuffering-Rate und Wiedergabefehler zu messen.
3. Remote-Kill-Switch und schnelles Rollback
Wenn in der Produktion auf einem bestimmten Gerätemodell oder einer bestimmten Betriebssystemversion eine Regression auftritt, kannst du den Canary-Modus (oder die entsprechende Flag-ID) über die serverseitige Konfiguration remote deaktivieren. Dadurch wird die Bibliothek für betroffene Nutzer sofort auf das stabile, alte Fallback-Verhalten zurückgesetzt, ohne dass ein Notfall-Hotfix oder ein Binär-Release für die App erforderlich ist.
Canary-Modus und Flags konfigurieren
Die Flags API bietet Methoden zum Steuern des globalen Canary-Modus und einzelner Flag-Überschreibungen.
Globaler Canary-Modus
So aktivieren oder deaktivieren Sie alle Optimierungen, die im Canary-Modus enthalten sind:
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);
Einzelne Flags überschreiben
Sie können bestimmte Flags auch unabhängig von der globalen Canary-Modus-Einstellung explizit aktivieren oder deaktivieren:
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);
Explizite Überschreibungen haben immer Vorrang vor der globalen Canary-Modus-Standardeinstellung.
Flag-Status prüfen
So prüfen Sie, ob der Canary-Modus oder ein bestimmtes Flag in Ihrem Code aktiv ist:
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);
Reihenfolge der Flag-Auflösung
Wenn Media3 prüft, ob eine Funktion zur Laufzeit aktiviert ist, wird der Status in der folgenden Reihenfolge aufgelöst:
- Explizites Überschreiben der Laufzeit: Wenn
enableFlagoderdisableFlagfür die Flag-ID aufgerufen wurde, wird dieser Überschreibungswert zurückgegeben. - Statischer Bibliotheksstatus: Wenn das Flag statisch deaktiviert ist (z. B. ein Feature in der frühen Entwicklungsphase, das noch nicht für den Canary-Modus bereit ist) oder statisch aktiviert ist (ein Feature, das den Canary-Modus verlassen hat und einen temporären Opt-out-Fallback beibehält), wird dieser statische Wert zurückgegeben.
- Canary-Modus-Status: Andernfalls folgt das Flag der globalen Canary-Modus-Einstellung (aktiviert, wenn der Canary-Modus
trueist, deaktiviert, wenn erfalseist).
Anforderungen an die Initialisierung
Konfiguriere Flags, bevor du Media3-Komponenten wie ExoPlayer, Transformer oder MediaSession instanziierst:
- Frühe Einrichtung: Konfigurieren Sie
Flagswährend des Anwendungsstarts (z. B. inApplication.onCreate) oder vor der Initialisierung der Medienebene Ihrer App. - Threadsicherheit: Media3-Komponenten lesen Flags während der Instanziierung und geben diese Werte an interne Wiedergabe- und Verarbeitungsthreads weiter. Achten Sie darauf, dass die Flag-Konfiguration vor dem Erstellen von Media3-Komponenten erfolgt. Das Ändern von Flags, während Player oder Transformer aktiv ausgeführt werden, wird nicht unterstützt.
In Remote-Konfiguration einbinden
Eine empfohlene Architektur besteht darin, drei Parameter auf Ihrer Remote-Konfigurationsplattform bereitzustellen:
media3_canary_mode_enabled(boolesch): Globale Ein-/Aus-Schaltfläche für den Canary-Modus (Standardwert isttrue).media3_force_enable_flags(Liste von Ganzzahlen): Bestimmte Flag-IDs, die für gezielte Tests zwingend aktiviert werden sollen.media3_force_disable_flags(Liste von Ganzzahlen): Bestimmte Flag-IDs, die zwangsweise deaktiviert werden sollen, wenn ein Problem erkannt wird.
Wenden Sie diese Werte beim Start an, bevor Sie Player-Instanzen erstellen:
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); } }
Mit Flags testen
Wenn Sie Unit-Tests oder Robolectric-Tests für Codepfade schreiben, die von Funktions-Flags betroffen sind, verwenden Sie androidx.media3.test.utils.Media3FlagsRule (verfügbar im Modul media3-test-utils), um zu verhindern, dass sich die Tests gegenseitig im statischen Zustand beeinflussen.
Automatische Bereinigung mit Media3FlagsRule
Wenn Sie Media3FlagsRule hinzufügen, werden alle Flag-Überschreibungen und Canary-Modus-Änderungen nach jedem Test automatisch zurückgesetzt:
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... } }
Parametrisierte Tests
Sie können Media3FlagsRule mit den Annotationen @BindFlag und @BindCanaryMode kombinieren, um parametrisierte Tests für verschiedene Flag-Zustände auszuführen:
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. } }
Diagnose und Logging
Media3 bietet Diagnosetools, mit denen du aktive Flags und Canary-Modus-Status während der Wiedergabeinitialisierung und zur Laufzeit prüfen kannst.
Initialisierungslogs
Wenn eine ExoPlayer-Instanz initialisiert wird, werden der aktive Canary-Status und alle expliziten Überschreibungen zusammen mit der Bibliotheksversion in logcat ausgegeben:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON]
Wenn Überschreibungen aktiv sind, werden nur die Abweichungen vom Standardstatus aufgeführt:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON, Overrides: enabled=[1], disabled=[3]]
Programmatische Prüfung
Sie können den formatierten Diagnosestring oder die Listen mit Abfrageüberschreibungen programmatisch abrufen, um beispielsweise den Flag-Status in die Absturzberichte oder Analysen Ihrer App aufzunehmen:
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();
Lebenszyklus von Flags
Flags in Media3 sind temporär:
- Entwicklung: Eine neue Optimierung oder Funktion wird hinter einer Flag-ID in
Flags.javahinzugefügt. - Canary-Modus: Sobald die Funktion verifiziert und für die allgemeine Verwendung bereit ist, ist sie im Canary-Modus für alle Releases aktiv.
- Hochstufung und Bereinigung: Nach einer Testphase, in der die Stabilität in der Produktion nachgewiesen wurde, wird das Feature in der Bibliothek dauerhaft aktiviert. Die Flag-Konstante, die Fallback-Codepfade und die bedingten Prüfungen werden entfernt.
Wenn Sie ein Problem mit einem Funktions-Flag feststellen, melden Sie es bitte im AndroidX Media3 GitHub Issue Tracker, damit das Team es beheben kann, bevor die Funktion dauerhaft aktiviert wird.