Jetpack Media3 會定義 Player
介面,概述播放影片和音訊檔案的基本功能。ExoPlayer
是此介面在 Media3 中的預設實作。建議您使用 ExoPlayer,因為 ExoPlayer 具備一系列能涵蓋大多數播放用途的全方位功能,而且可自訂,處理任何其他用途。ExoPlayer 還會抽取裝置和 OS 片段,讓程式碼在整個 Android 生態系統中以一致的方式運作。ExoPlayer 包含:
本頁將介紹建構播放應用程式的部分重要步驟,詳情請參閱 Media3 ExoPlayer 的完整指南。
開始使用
如要開始使用,請新增 Jetpack Media3 的 ExoPlayer、UI 和常見模組依附元件:
implementation "androidx.media3:media3-exoplayer:1.3.1" implementation "androidx.media3:media3-ui:1.3.1" implementation "androidx.media3:media3-common:1.3.1"
視用途而定,您可能也需要其他 Media3 的模組,例如 exoplayer-dash
,才能播放 DASH 格式的串流。
請務必將 1.3.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.3.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
時設定回呼物件。
當控制器即將連線至媒體工作階段時,系統會呼叫 onConnect()
方法。您可以使用系統提供的 ControllerInfo
決定是否要接受或拒絕要求。如需相關範例,請參閱 Media3 工作階段試用版應用程式。
連線後,控制器就能傳送播放指令到工作階段。然後,工作階段會將這些指令委派給玩家。工作階段會自動處理 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; }
連線至您的使用者介面
媒體工作階段現在位於與播放器 UI 所在的 Activity
或 Fragment
不同的 Service
,您可以使用 MediaController
連結兩者。在 Activity
或 Fragment
的 onStart()
方法中,為 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
(例如 Activity
的 onStop()
生命週期方法) 時呼叫 MediaController.releaseFuture()
,再釋出 MediaController
。
發布通知
啟用前景服務後,才能在啟用狀態下發布通知。MediaSessionService
會以 MediaNotification
的形式自動為您建立 MediaStyle
通知。如要提供自訂通知,請使用 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()
用於當用戶端要求內容樹狀結構中MediaItem
的子項onGetSearchResult()
用於指定查詢內容樹狀結構中的搜尋結果
相關的回呼方法會包含 LibraryParams
物件,並針對用戶端應用程式感興趣的內容樹狀結構類型提供額外信號。