Jetpack Media3 定義了 Player
介面,其中列出播放影片和音訊檔案的基本功能。ExoPlayer
是 Media3 中這個介面的預設實作項目。建議使用 ExoPlayer,因為它提供完整的功能組合,涵蓋大多數播放用途,而且可自訂,以處理您可能有的任何其他用途。ExoPlayer 也會將裝置和 OS 片段化抽離,讓您的程式碼在整個 Android 生態系統中保持一致運作。ExoPlayer 包含:
- 支援播放清單
- 支援多種漸進式和自適應串流格式
- 支援用戶端和伺服器端廣告插播
- 支援受 DRM 保護的播放內容
本頁面將逐步說明建構播放應用程式的一些重要步驟,如需更多詳細資料,請參閱 Media3 ExoPlayer 的完整指南。
開始使用
如要開始使用,請新增 Jetpack Media3 的 ExoPlayer、UI 和 Common 模組依附元件:
implementation "androidx.media3:media3-exoplayer:1.7.1" implementation "androidx.media3:media3-ui:1.7.1" implementation "androidx.media3:media3-common:1.7.1"
視用途而定,您可能還需要 Media3 的其他模組,例如 exoplayer-dash
,才能播放 DASH 格式的串流。
請務必將 1.7.1
替換為偏好的程式庫版本。如要查看最新版本,請參閱版本資訊。
建立媒體播放器
使用 Media3 時,您可以選擇使用隨附的 Player
介面實作項目 ExoPlayer
,也可以自行建構自訂實作項目。
建立 ExoPlayer
建立 ExoPlayer
執行個體最簡單的方法如下:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
您可以在 Activity
、Fragment
或 Service
的 onCreate()
生命週期方法中建立媒體播放器。
Builder
包含一系列自訂選項,您可能會感興趣,例如:
setAudioAttributes()
設定音訊焦點處理方式setHandleAudioBecomingNoisy()
設定音訊輸出裝置中斷連線時的播放行為setTrackSelector()
設定曲目選取
Media3 提供 PlayerView
UI 元件,可加入應用程式的版面配置檔案。這個元件會封裝 PlayerControlView
(用於播放控制項)、SubtitleView
(用於顯示字幕) 和 Surface
(用於算繪影片)。
準備播放器
使用 setMediaItem()
和 addMediaItem()
等方法,將媒體項目新增至播放清單,以便播放。然後呼叫 prepare()
,開始載入媒體並取得必要資源。
應用程式處於前景時,您才應執行這些步驟。如果播放器處於 Activity
或 Fragment
狀態,表示您在 API 級別 24 以上版本中,於 onStart()
生命週期方法準備播放器,或在 API 級別 23 以下版本中,於 onResume()
生命週期方法準備播放器。如要準備Service
中的球員,請前往onCreate()
。
控制播放器
準備好播放器後,您可以在播放器上呼叫方法來控制播放作業,例如:
play()
和pause()
開始及暫停播放seekTo()
,在目前的媒體項目中跳轉至特定位置seekToNextMediaItem()
和seekToPreviousMediaItem()
,瀏覽播放清單
繫結至播放器後,PlayerView
或 PlayerControlView
等 UI 元件就會相應更新。
釋放球員
播放影片可能需要資源 (例如影片解碼器),因此不再需要播放器時,請務必呼叫 release()
釋出資源。
如果播放器位於 Activity
或 Fragment
中,請在 API 級別 24 以上版本的 onStop()
生命週期方法中,或在 API 級別 23 以下版本的 onPause()
方法中,釋放播放器。如果球員位於 Service
,你可以將其釋出至 onDestroy()
。
使用媒體工作階段管理播放
在 Android 上,媒體工作階段提供標準化方式,可跨程序界線與媒體播放器互動。將媒體工作階段連結至播放器,即可在外部宣傳媒體播放作業,並接收來自外部來源的播放指令,例如整合行動裝置和大螢幕裝置上的系統媒體控制項。
如要使用媒體工作階段,請新增 Media3 Session 模組的依附元件:
implementation "androidx.media3:media3-session:1.7.1"
建立媒體工作階段
初始化播放器後,您可以按照下列方式建立 MediaSession
:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
Media3 會自動將 Player
的狀態與 MediaSession
的狀態同步。這項功能適用於任何 Player
實作項目,包括 ExoPlayer
、CastPlayer
或自訂實作項目。
將控制權授予其他用戶端
用戶端應用程式可以實作媒體控制器,控制媒體工作階段的播放作業。如要接收這些要求,請在建構 MediaSession
時設定 callback 物件。
當控制器即將連線至媒體工作階段時,系統會呼叫 onConnect()
方法。您可以根據提供的 ControllerInfo
決定是否接受或拒絕要求。如需相關範例,請參閱 Media3 Session 示範應用程式。
連線後,控制器就能將播放指令傳送至工作階段。然後將這些指令委派給播放器。工作階段會自動處理 Player
介面中定義的播放和播放清單指令。
其他回呼方法可讓您處理要求,例如自訂播放指令和修改播放清單。這些回呼同樣包含 ControllerInfo
物件,因此您可以根據要求逐一判斷存取控管機制。
在背景播放媒體
如要在應用程式不在前景時繼續播放媒體 (例如在使用者未開啟應用程式時播放音樂、有聲書或 Podcast),請將 Player
和 MediaSession
封裝在前景服務中。為此,Media3 提供 MediaSessionService
介面。
實作 MediaSessionService
建立擴充 MediaSessionService
的類別,並在 onCreate()
生命週期方法中例項化 MediaSession
。
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your Player and MediaSession in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
在資訊清單中,使用 MediaSessionService
意圖篩選器建立 Service
類別,並要求 FOREGROUND_SERVICE
權限來執行前景服務:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
最後,在您建立的類別中,覆寫 onGetSession()
方法,控管用戶端對媒體工作階段的存取權。傳回 MediaSession
即可接受連線要求,傳回 null
則可拒絕要求。
Kotlin
// This example always accepts the connection request override fun onGetSession( controllerInfo: MediaSession.ControllerInfo ): MediaSession? = mediaSession
Java
@Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { // This example always accepts the connection request return mediaSession; }
連結至使用者介面
現在媒體工作階段與 Activity
或播放器 UI 所在的 Fragment
分開,因此您可以使用 MediaController
將兩者連結在一起。Service
在 Activity
或 Fragment
的 onStart()
方法中,使用您的 UI 為 MediaSession
建立 SessionToken
,然後使用 SessionToken
建構 MediaController
。建構 MediaController
是非同步作業。
Kotlin
override fun onStart() { val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java)) val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener( { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()) }, MoreExecutors.directExecutor() ) }
Java
@Override public void onStart() { SessionToken sessionToken = new SessionToken(this, new ComponentName(this, PlaybackService.class)); ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(this, sessionToken).buildAsync(); controllerFuture.addListener(() -> { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()); }, MoreExecutors.directExecutor()) }
MediaController
會實作 Player
介面,因此您可以使用 play()
和 pause()
等相同方法來控制播放作業。與其他元件類似,請記得在不再需要 MediaController
時釋出,例如呼叫 MediaController.releaseFuture()
,釋出 Activity
的 onStop()
生命週期方法。
發布通知
前景服務必須在啟動時發布通知。A
MediaSessionService
會自動為您建立 MediaStyle
通知,並以 MediaNotification
形式顯示。
如要提供自訂通知,請使用 DefaultMediaNotificationProvider.Builder
建立 MediaNotification.Provider
,或是建立提供者介面的自訂實作項目。使用 setMediaNotificationProvider
,將供應商新增至 MediaSession
。
宣傳內容庫
MediaLibraryService
是以 MediaSessionService
為基礎,可讓用戶端應用程式瀏覽應用程式提供的媒體內容。用戶端應用程式會實作 MediaBrowser
,與 MediaLibraryService
互動。
實作 MediaLibraryService
與實作 MediaSessionService
類似,但您應在 onGetSession()
中傳回 MediaLibrarySession
,而非 MediaSession
。相較於 MediaSession.Callback
,MediaLibrarySession.Callback
包含其他方法,可讓瀏覽器用戶端瀏覽程式庫服務提供的內容。
與 MediaSessionService
類似,在資訊清單中宣告 MediaLibraryService
,並要求 FOREGROUND_SERVICE
權限來執行前景服務:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
上述範例包含 MediaLibraryService
的意圖篩選器,以及為了回溯相容性而加入的舊版 MediaBrowserService
。額外的意圖篩選器可讓使用 MediaBrowserCompat
API 的用戶端應用程式辨識 Service
。
MediaLibrarySession
可讓您以樹狀結構提供內容資料庫,並使用單一根 MediaItem
。樹狀結構中的每個 MediaItem
都可以有任意數量的子項 MediaItem
節點。您可以根據用戶端應用程式的要求,提供不同的根或樹狀結構。舉例來說,您傳回給尋找建議媒體項目清單的用戶端的樹狀結構,可能只包含根 MediaItem
和單一層級的子項 MediaItem
節點,而您傳回給其他用戶端應用程式的樹狀結構,則可能代表更完整的內容庫。
建立 MediaLibrarySession
MediaLibrarySession
會擴充 MediaSession
API,加入內容瀏覽 API。相較於 MediaSession
回呼,MediaLibrarySession
回呼新增了下列方法:
onGetLibraryRoot()
當用戶端要求內容樹狀結構的根MediaItem
時onGetChildren()
for when a client requests the children of aMediaItem
in the content treeonGetSearchResult()
用戶端針對特定查詢要求內容樹狀結構的搜尋結果時
相關回呼方法會包含 LibraryParams
物件,其中含有用戶端應用程式感興趣的內容樹狀結構類型相關額外信號。