Media3 在其程式庫中導入新的最佳化、行為改善和架構強化功能。雖然這些變更在發布前都經過徹底測試和驗證,但 Media3 包含以Canary 模式為中心的集中式功能旗標基礎架構 (androidx.media3.common.Flags),可讓應用程式控管採用新行為的方式和時間。
本頁面說明初期測試版本模式和功能旗標的運作方式,以及如何在應用程式中使用這些功能,降低各版本發布的升級風險、執行控管式推出作業,以及設定緊急復原。
總覽
Canary 模式會將新推出的經驗證程式庫改善項目,歸入統一的全域切換鈕:
- 預設啟用:在標準 Media3 版本中,Canary 模式預設為啟用 (
true)。這樣一來,應用程式就能自動享有安全效能強化、最佳化和新功能。 - 選擇不採用和復原功能:應用程式可以在執行階段全面停用 Canary 模式,或個別覆寫特定功能旗標。
- 完全不需複雜的連結:旗標是透過
common模組中的中央Flags類別管理,因此不需要在不同元件中使用自訂 setter 或設定物件。
為什麼要在應用程式中使用標記?
雖然 Canary 模式預設為啟用,但將 Flags 整合至應用程式的設定或實驗架構,可帶來多項好處:
1. 降低版本升級風險
在正式環境中升級程式庫的主要或次要版本,可能會在特定原始設備製造商 (OEM) 裝置或自訂媒體管道上,引發非預期的互動。更新 Media3 時,您可以使用初期測試模式和遠端設定,在不同版本之間採用更安全的升級流程:
- 在停用初期測試模式的情況下推送更新:發布關閉初期測試模式的新 Media3 版本,大致上會保留先前版本 (啟用初期測試模式) 的功能集,讓您在採用新行為前,先驗證正式環境中的基準程式庫穩定性和一般錯誤修正。
- 逐步啟用初期測試模式:使用遠端設定,在使用者同類群組中分階段啟用初期測試模式 (例如 5% → 25% → 100%),或執行 A/B 實驗來評估指標影響。
- 視需要復原:如果特定裝置發生迴歸,可以從遠端停用 Canary 模式或特定旗標 ID,不必緊急發布應用程式。
- 預設採用:驗證完成後,預設啟用初期測試模式,直到下次版本升級,先前驗證的初期測試功能才會永久生效。
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. 控管階段式推出和 A/B 測試
您可以將 Flags 連接至遠端設定或實驗系統,而不是一次向所有使用者公開新的程式庫行為。
您可以分階段啟用 Canary 模式 (例如 5% 的使用者 → 25% → 100%),或執行 A/B 實驗,評估新最佳化措施對核心播放指標的影響,例如啟動延遲時間、重新緩衝處理率和播放失敗率。
3. 遠端終止參數和快速復原
如果特定裝置型號或 OS 版本的正式版發生迴歸,您可以使用伺服器端設定,從遠端停用 Canary 模式 (或負責的特定旗標 ID)。這會立即將程式庫還原為穩定、舊版的備用行為,適用於受影響的使用者,不需要緊急應用程式 hotfix 或二進位檔版本。
設定初期測試模式和旗標
Flags API 提供控制全域 Canary 模式和個別旗標覆寫的方法。
全域 Canary 模式
如要啟用或停用 Canary 模式涵蓋的所有強化功能,請按照下列步驟操作:
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);
覆寫個別旗標
您也可以明確啟用或停用特定旗標,不受全域 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);
明確覆寫的優先順序一律高於全域初期測試模式預設值。
正在檢查標記狀態
如要檢查程式碼是否啟用 Canary 模式或特定旗標,請按照下列步驟操作:
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);
旗標解析順序
Media3 在執行階段檢查功能是否啟用時,會依下列順序解析狀態:
- 明確執行階段覆寫:如果針對旗標 ID 呼叫
enableFlag或disableFlag,系統會傳回該覆寫值。 - 靜態程式庫狀態:如果旗標已靜態停用 (例如尚未準備好進入 Canary 模式的早期開發功能),或靜態啟用 (從 Canary 模式畢業的功能,保留暫時停用的備用方案),則會傳回該靜態值。
- Canary 模式狀態:否則,旗標會遵循全域 Canary 模式設定 (如果 Canary 模式為
true,則啟用;如果為false,則停用)。
初始化規定
請先設定旗標,再例項化任何 Media3 元件 (例如 ExoPlayer、Transformer 或 MediaSession):
- 提早設定:在應用程式啟動期間 (例如在
Application.onCreate內) 或初始化應用程式的媒體層之前,設定Flags。 - 執行緒安全:Media3 元件會在例項化期間讀取旗標,並將這些值傳播至內部播放和處理執行緒。請務必先設定旗標,再建立 Media3 元件。不支援在播放器或轉換器執行時修改標記。
與遠端設定整合
建議的架構是在遠端設定平台中公開三個參數:
media3_canary_mode_enabled(布林值):Canary 模式的全域切換鈕 (預設為true)。media3_force_enable_flags(整數清單):要強制啟用指定試用版的特定旗標 ID。media3_force_disable_flags(整數清單):如果發現問題,要強制停用的特定旗標 ID。
請在啟動期間套用這些值,然後再建立播放器執行個體:
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); } }
使用旗標進行測試
為受功能旗標影響的程式碼路徑編寫單元測試或 Robolectric 測試時,請使用 androidx.media3.test.utils.Media3FlagsRule (位於 media3-test-utils 模組),確保測試不會互相干擾靜態狀態。
使用 Media3FlagsRule 自動清除
新增 Media3FlagsRule 可確保每次測試後,所有旗標覆寫和 Canary 模式修改都會自動重設:
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... } }
參數化測試
您可以結合 Media3FlagsRule 與 @BindFlag 和 @BindCanaryMode 註解,在不同旗標狀態下執行參數化測試:
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. } }
診斷和記錄
Media3 提供診斷工具,可在播放初始化和執行階段,驗證有效旗標和 Canary 模式狀態。
初始化記錄
ExoPlayer 執行個體初始化時,會將有效的 Canary 狀態和任何明確覆寫值,連同程式庫版本一併輸出至 logcat:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON]
如果覆寫值處於啟用狀態,系統只會列出與預設狀態不同的值:
ExoPlayerImpl: Init 59a18ab [AndroidXMedia3/1.10.1] [flame, Pixel 4, Google, 33] [Canary:ON, Overrides: enabled=[1], disabled=[3]]
程式輔助檢查
您可以透過程式輔助方式擷取格式化的診斷字串或查詢覆寫清單 (例如在應用程式的當機報告或數據分析中加入標記狀態):
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();
標記生命週期
Media3 中的旗標是暫時性的:
- 開發:在
Flags.java的旗標 ID 後方新增最佳化或功能。 - 初期測試模式:功能通過驗證並可供一般使用後,就會在各版本的初期測試模式中啟用。
- 升級和清理:經過一段時間的觀察,證明功能在正式環境中穩定運作後,就會升級為永久啟用,並移除旗標常數、備用程式碼路徑和條件檢查。
如果遇到功能旗標相關問題,請在 AndroidX Media3 GitHub Issue Tracker 提交報告,讓團隊在永久升級前解決問題。