目前使用獨立 com.google.android.exoplayer2
程式庫和 androidx.media
的應用程式應遷移至 androidx.media3
。使用遷移指令碼,將 Gradle 建構檔案、Java 和 Kotlin 來源檔案,以及 XML 版面配置檔案從 ExoPlayer 2.19.1
遷移至 AndroidX Media3 1.1.1
。
總覽
在遷移前,請先詳閱下列各節,進一步瞭解新 API 的優點、要遷移的 API,以及應用程式專案應符合的先決條件。
為何要遷移至 Jetpack Media3
- 這是新的 ExoPlayer 家,但
com.google.android.exoplayer2
停止服務。 - 使用
MediaBrowser
/MediaController
跨元件/程序存取 Player API。 - 使用
MediaSession
和MediaController
API 的擴充功能。 - 透過精細的存取權控管機制通告播放功能。
- 移除
MediaSessionConnector
和PlayerNotificationManager
,即可簡化應用程式。 - 與媒體相容性用戶端 API (
MediaBrowserCompat
/MediaControllerCompat
/MediaMetadataCompat
) 向下相容
要遷移至 AndroidX Media3 的媒體 API
- ExoPlayer 及其擴充功能
這包括舊版 ExoPlayer 專案的所有模組,但不包括已停用的 mediasession 模組。視com.google.android.exoplayer2
中的套件而定,可以使用遷移指令碼遷移應用程式或模組。 - MediaSessionConnector (取決於
androidx.media:media:1.4.3+
的androidx.media.*
套件)
移除MediaSessionConnector
,改用androidx.media3.session.MediaSession
。 - MediaBrowserServiceCompat (取決於
androidx.media:media:1.4.3+
的androidx.media.*
套件)
將androidx.media.MediaBrowserServiceCompat
的子類別遷移至androidx.media3.session.MediaLibraryService
,並將使用MediaBrowserCompat.MediaItem
的程式碼遷移至androidx.media3.common.MediaItem
。 - MediaBrowserCompat (取決於
androidx.media:media:1.4.3+
的android.support.v4.media.*
套件)
使用MediaBrowserCompat
或MediaControllerCompat
遷移用戶端程式碼,以便搭配androidx.media3.common.MediaItem
使用androidx.media3.session.MediaBrowser
。
必要條件
確認專案處於來源控管狀態
確認遷移工具套用指令碼後,您可以輕鬆還原變更。如果您尚未對專案進行原始碼控管,不妨立即開始使用。如果您基於某些原因不想這樣做,請先備份專案,再開始遷移作業。
更新應用程式
建議您將專案更新為使用最新版本的 ExoPlayer 程式庫,並移除所有對已淘汰方法的呼叫。如果您想使用指令碼進行遷移,請將要更新的版本與指令碼處理的版本進行比對。
將應用程式的 compileSdkVersion 提高至至少 32。
將 Gradle 和 Android Studio Gradle 外掛程式升級為支援以上更新依附元件的最新版本。例如:
- Android Gradle 外掛程式版本:7.1.0
- Gradle 版本:7.4
取代所有使用星號 (*) 的萬用字元匯入陳述式,並使用完全限定的匯入陳述式:刪除萬用字元匯入陳述式,然後使用 Android Studio 匯入完全限定的陳述式 (F2 - Alt/Enter、F2 - Alt/Enter、...)。
從
com.google.android.exoplayer2.PlayerView
遷移至com.google.android.exoplayer2.StyledPlayerView
。這是必要的,因為 AndroidX Media3 中沒有com.google.android.exoplayer2.PlayerView
的等價項目。
遷移支援指令碼的 ExoPlayer
這段指令碼可協助您從 com.google.android.exoplayer2
遷移至 androidx.media3
底下的全新套件和模組結構。此指令碼會對專案套用一些驗證檢查,並在驗證失敗時顯示警告。否則,它會在以 Java 或 Kotlin 編寫的 Android Gradle 專案資源中,套用已重新命名的類別和套件的對應項目。
usage: ./media3-migration.sh [-p|-c|-d|-v]|[-m|-l [-x <path>] [-f] PROJECT_ROOT]
PROJECT_ROOT: path to your project root (location of 'gradlew')
-p: list package mappings and then exit
-c: list class mappings (precedence over package mappings) and then exit
-d: list dependency mappings and then exit
-l: list files that will be considered for rewrite and then exit
-x: exclude the path from the list of file to be changed: 'app/src/test'
-m: migrate packages, classes and dependencies to AndroidX Media3
-f: force the action even when validation fails
-v: print the exoplayer2/media3 version strings of this script
-h, --help: show this help text
使用遷移指令碼
從與已更新應用程式的版本相對應的 GitHub 上,從 ExoPlayer 專案的標記下載遷移指令碼:
curl -o media3-migration.sh \ "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
將指令碼設為可執行狀態:
chmod 744 media3-migration.sh
使用
--help
執行指令碼,瞭解相關選項。使用
-l
執行指令碼,即可列出已選取用於遷移的檔案組合 (使用-f
可強制列出清單,且不會顯示警告):./media3-migration.sh -l -f /path/to/gradle/project/root
使用
-m
執行指令碼,將套件、類別和模組對應至 Media3。使用-m
選項執行指令碼,即可將變更套用至所選檔案。- 在驗證錯誤處停止,但不進行變更
./media3-migration.sh -m /path/to/gradle/project/root
- 強制執行
如果指令碼發現違反先決條件,可以使用
-f
標記強制執行遷移作業:./media3-migration.sh -m -f /path/to/gradle/project/root
# list files selected for migration when excluding paths
./media3-migration.sh -l -x "app/src/test/" -x "service/" /path/to/project/root
# migrate the selected files
./media3-migration.sh -m -x "app/src/test/" -x "service/" /path/to/project/root
使用 -m
選項執行指令碼後,請完成下列手動步驟:
- 檢查指令碼如何變更程式碼:使用差異工具並修正潛在問題 (如果您認為指令碼在未傳遞
-f
選項的情況下引入了一般問題,請考慮提交錯誤)。 - 建立專案:使用
./gradlew clean build
,或在 Android Studio 中依序選擇「File」>「Sync Project with Gradle Files」,然後依序選擇「Build」>「Clean project」和「Build」>「Rebuild project」 (在 Android Studio 的「Build - Build Output」分頁監控建構作業)。
建議的後續步驟:
- 解決採用不穩定的 API 相關錯誤。
- 取代已淘汰的 API 呼叫:使用建議的替代 API。將游標懸停在 Android Studio 中的警告上,並參閱已淘汰符號的 JavaDoc,找出可用於取代指定呼叫的項目。
- 排序匯入陳述式:在 Android Studio 中開啟專案,然後在專案檢視器中按一下套件資料夾節點,並在包含已變更來源檔案的套件上選擇「Optimize imports」。
以 androidx.media3.session.MediaSession
取代 MediaSessionConnector
。
在舊版 MediaSessionCompat
環境中,MediaSessionConnector
負責將玩家的狀態與工作階段狀態同步,並接收需要委派給適當的玩家方法的控制器指令。使用 AndroidX Media3 時,由 MediaSession
直接執行,不需要使用連接器。
移除所有 MediaSessionConnector 的參照和用法:如果您使用自動化指令碼遷移 ExoPlayer 類別和套件,那麼指令碼可能會讓您的程式碼處於無法解析的
MediaSessionConnector
無法編譯的狀態。您嘗試建構或啟動應用程式時,Android Studio 會顯示錯誤的程式碼。在維護依附元件的
build.gradle
檔案中,將實作依附元件新增至 AndroidX Media3 工作階段模組,並移除舊版依附元件:implementation "androidx.media3:media3-session:1.4.1"
將
MediaSessionCompat
替換為androidx.media3.session.MediaSession
。在建立舊版
MediaSessionCompat
的程式碼網站中,使用androidx.media3.session.MediaSession.Builder
建構MediaSession
。傳遞玩家,以建構工作階段建構工具。val player = ExoPlayer.Builder(context).build() mediaSession = MediaSession.Builder(context, player) .setSessionCallback(MySessionCallback()) .build()
根據應用程式需求實作
MySessionCallback
。這不是必要的步驟。如果您想讓控制器將媒體項目新增至播放器,請實作MediaSession.Callback.onAddMediaItems()
。它提供各種目前和舊版 API 方法,可將媒體項目新增至播放器,以回溯相容的方式播放。這包括 Media3 控制器的MediaController.set/addMediaItems()
方法,以及舊版 API 的TransportControls.prepareFrom*/playFrom*
方法。您可以在工作階段示範應用程式的PlaybackService
中,找到onAddMediaItems
的實作範例。在遷移前銷毀工作階段的程式碼位置釋放媒體工作階段:
mediaSession?.run { player.release() release() mediaSession = null }
Media3 中的 MediaSessionConnector
功能
下表列出 Media3 API,可處理先前在 MediaSessionConnector
中實作的功能。
MediaSessionConnector | AndroidX Media3 |
---|---|
CustomActionProvider |
MediaSession.Callback.onCustomCommand()/
MediaSession.setCustomLayout() |
PlaybackPreparer |
MediaSession.Callback.onAddMediaItems()
(prepare() 會在內部呼叫)
|
QueueNavigator |
ForwardingPlayer |
QueueEditor |
MediaSession.Callback.onAddMediaItems() |
RatingCallback |
MediaSession.Callback.onSetRating() |
PlayerNotificationManager |
DefaultMediaNotificationProvider/
MediaNotification.Provider |
將 MediaBrowserService
遷移至 MediaLibraryService
AndroidX Media3 引進了 MediaLibraryService
,用來取代 MediaBrowserServiceCompat
。MediaLibraryService
和其超類別 MediaSessionService
的 JavaDoc 提供了 API 和服務的非同步程式設計模式的良好介紹。
MediaLibraryService
與 MediaBrowserService
具有回溯相容性。使用 MediaBrowserCompat
或 MediaControllerCompat
的用戶端應用程式在連線至 MediaLibraryService
時,可在不變更程式碼的情況下繼續運作。對用戶端而言,無論應用程式是使用 MediaLibraryService
還是舊版 MediaBrowserServiceCompat
,都是透明的。
為確保回溯相容性,您需要在
AndroidManifest.xml
中為服務註冊兩個服務介面。這樣一來,用戶端就能透過必要的服務介面找到您的服務:<service android:name=".MusicService" android:exported="true"> <intent-filter> <action android:name="androidx.media3.session.MediaLibraryService"/> <action android:name="android.media.browse.MediaBrowserService" /> </intent-filter> </service>
在維護依附元件的
build.gradle
檔案中,將實作依附元件新增至 AndroidX Media3 工作階段模組,並移除舊版依附元件:implementation "androidx.media3:media3-session:1.4.1"
將服務變更為沿用
MediaLibraryService
,而不是MediaBrowserService
如先前所述,MediaLibraryService
與舊版MediaBrowserService
相容。因此,服務提供給用戶端的更廣泛 API 仍維持不變。因此,應用程式可能可以保留實作MediaBrowserService
所需的大部分邏輯,並根據新的MediaLibraryService
進行調整。與舊版
MediaBrowserServiceCompat
相比,主要差異如下:實作服務生命週期方法:需要在服務本身覆寫的方法是
onCreate/onDestroy
,應用程式會在其中分配/釋出程式庫工作階段、播放器和其他資源。除了標準服務生命週期方法之外,應用程式還需要覆寫onGetSession(MediaSession.ControllerInfo)
,才能傳回在onCreate
中建構的MediaLibrarySession
。實作 MediaLibraryService.MediaLibrarySessionCallback:建構工作階段需要實作實際的網域 API 方法的
MediaLibraryService.MediaLibrarySessionCallback
。因此,您將覆寫MediaLibrarySession.Callback
的 方法,而非覆寫舊版服務的 API 方法。然後使用回呼建構
MediaLibrarySession
:mediaLibrarySession = MediaLibrarySession.Builder(this, player, MySessionCallback()) .build()
請參閱 API 說明文件中的「MediaLibrarySessionCallback 完整 API」。
實作
MediaSession.Callback.onAddMediaItems()
:回呼onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>)
會提供各種目前和舊版 API 方法,這些方法會將媒體項目新增至播放器,以回溯相容的方式進行播放。這包括 Media3 控制器的MediaController.set/addMediaItems()
方法,以及舊版 API 的TransportControls.prepareFrom*/playFrom*
方法。您可以在工作階段示範應用程式的PlaybackService
中,找到回呼的實作範例。AndroidX Media3 使用
androidx.media3.common.MediaItem
,而非 MediaBrowserCompat.MediaItem 和 MediaMetadataCompat。與舊版類別繫結的程式碼部分需要據此變更,或改為對應至 Media3MediaItem
。一般非同步程式設計模型變更為
Futures
,相對於MediaBrowserServiceCompat
的可卸離Result
方法。您的服務實作可以傳回非同步的ListenableFuture
,而非分離結果,或傳回即時 Future 以便直接傳回值。
移除 PlayerNotificationManager
MediaLibraryService
會自動支援媒體通知,且在使用 MediaLibraryService
或 MediaSessionService
時可移除 PlayerNotificationManager
。
應用程式可以在 onCreate()
中設定自訂 MediaNotification.Provider
來取代 DefaultMediaNotificationProvider
,藉此自訂通知。接著,MediaLibraryService
會視需要在前景啟動服務。
只要覆寫 MediaLibraryService.updateNotification()
,應用程式就能進一步取得發布通知的完整權限,並視需要在前景啟動/停止服務。
使用 MediaBrowser 遷移用戶端程式碼
在 AndroidX Media3 中,MediaBrowser
會實作 MediaController/Player
介面,且除了瀏覽媒體程式庫之外,可用於控制媒體播放。如果您必須在舊版中建立 MediaBrowserCompat
和 MediaControllerCompat
,只要在 Media3 中使用 MediaBrowser
,即可執行相同操作。
您可以建構 MediaBrowser
,並等待與服務建立連線:
scope.launch {
val sessionToken =
SessionToken(context, ComponentName(context, MusicService::class.java)
browser =
MediaBrowser.Builder(context, sessionToken))
.setListener(BrowserListener())
.buildAsync()
.await()
// Get the library root to start browsing the library.
root = browser.getLibraryRoot(/* params= */ null).await();
// Add a MediaController.Listener to listen to player state events.
browser.addListener(playerListener)
playerView.setPlayer(browser)
}
請參閱「在媒體工作階段中控管播放功能」,瞭解如何建立在背景控製播放作業的 MediaController
。
後續步驟和清理
不穩定的 API 錯誤
遷移至 Media3 後,您可能會看到與不穩定 API 用法相關的 Lint 錯誤。這些 API 可安全使用,而 Lint 錯誤是我們新的二進位相容性保證的副產品。如果您不需要嚴格的二進位檔相容性,可以使用 @OptIn
註解安全地隱藏這些錯誤。
背景
ExoPlayer 第 1 版和第 2 版都沒有嚴格保證,無法保證後續版本之間的程式庫二進位檔相容性。ExoPlayer API 介面在設計上非常大,讓應用程式能自訂播放過程中幾乎所有層面的設定。ExoPlayer 的後續版本偶爾會引入符號重新命名或其他破壞性變更 (例如介面上的新必要方法)。在大多數情況下,我們會透過推出新符號並在幾個版本中淘汰舊符號,以減輕這些中斷情形,讓開發人員有時間遷移其用途,但這不一定可行。
這些重大變更導致 ExoPlayer v1 和 v2 程式庫的使用者遇到兩個問題:
- 升級至 ExoPlayer 版本可能會導致程式碼停止編譯。
- 如果應用程式直接和透過中繼程式庫依附於 ExoPlayer,就必須確保這兩個依附元件的版本相同,否則二進位檔不相容可能會導致執行階段異常終止。
Media3 中的改善項目
Media3 保證部分 API 介面的二進位檔相容性。不保證二進位檔相容性的部分會標示為 @UnstableApi
。為了清楚區分這兩者,如果使用不穩定的 API 符號,系統會產生 Lint 錯誤,除非這些符號已加上 @OptIn
註解。
從 ExoPlayer 2.0 遷移至 Media3 後,您可能會看到許多不穩定的 API Lint 錯誤。這可能會讓 Media3 看起來比 ExoPlayer v2 更不穩定。但事實並非如此。Media3 API 的「不穩定」部分與 ExoPlayer v2 API 途徑的「整體」具有相同的穩定性,而 ExoPlayer v2 完全無法提供穩定的 Media3 API 途徑保證。差別在於,現在 Lint 錯誤會提醒您不同層級的穩定性。
處理不穩定的 API Lint 錯誤
如要進一步瞭解如何使用 @OptIn
為不穩定 API 的 Java 和 Kotlin 用法加上註解,請參閱這些 Lint 錯誤的疑難排解章節。
已淘汰的 API
您可能會發現,Android Studio 會將已淘汰 API 的呼叫劃掉。建議您將這類呼叫替換為適當的替代方案。將滑鼠遊標懸停在符號上,即可查看已改用哪個 API 的 JavaDoc。
程式碼範例和試用版應用程式
- AndroidX Media3 工作階段示範應用程式 (行動裝置和 WearOS)
- 自訂動作
- 系統 UI 通知、MediaButton/BT
- Google 助理播放控制項
- UAMP:Android 媒體播放器 (分支媒體 3) (行動裝置、AutomotiveOS)
- 系統 UI 通知、MediaButton/BT、播放內容繼續播放
- Google 助理/WearOS 播放控制
- AutomotiveOS:自訂指令和登入