使用 Media3 ExoPlayer 建立基本媒體播放器應用程式

Jetpack Media3 定義了 Player 介面,用於概述基本功能 影片和音訊檔案的播放。ExoPlayer 為預設實作方式 您之後要在 Media3 中使用這個介面的介面建議使用 ExoPlayer,因為其提供 功能完整的功能組合,涵蓋大部分的播放用途 再靈活自訂來處理其他用途ExoPlayer 也 去除裝置和 OS 零碎的零碎問題,確保程式碼能穩定運作 整個 Android 生態系統中ExoPlayer 包含下列項目:

本頁將逐步說明建立播放作業的重要步驟 應用程式。如需更多詳細資訊,請參閱完整指南 Media3 ExoPlayer

開始使用

如要開始使用,請新增 ExoPlayer、UI,以及 Jetpack Media3:

implementation "androidx.media3:media3-exoplayer:1.4.1"
implementation "androidx.media3:media3-ui:1.4.1"
implementation "androidx.media3:media3-common:1.4.1"

根據您的用途,可能也需要 Media3、 例如 exoplayer-dash,以 DASH 格式播放串流。

請務必將 1.4.1 替換為您偏好的 資源庫。請參閱版本資訊 即可查看最新版本

建立媒體播放器

在 Media3 中,您可以使用隨附的 Player 實作 您可以運用 ExoPlayer 介面,也可以自行建立實作項目。

建立 ExoPlayer

建立 ExoPlayer 例項最簡單的方式如下:

Kotlin

val player = ExoPlayer.Builder(context).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context).build();

您可以在以下項目的 onCreate() 生命週期方法中建立媒體播放器: 居住地的ActivityFragmentService

Builder 包括 您可能會感興趣的一系列自訂選項,例如:

Media3 提供 PlayerView UI 元件,您可以將其納入應用程式的 版面配置檔案。這個元件會封裝用於播放的 PlayerControlView 控制項、SubtitleView 顯示字幕、Surface 用於轉譯。 影片。

準備播放器

媒體項目加入 運用以下方法播放內容: setMediaItem()敬上 和 addMediaItem()。 然後呼叫 prepare() 以 開始載入媒體並取得必要資源。

您不應在應用程式於前景執行前執行這些步驟。如果您的 這表示玩家位於 ActivityFragment,亦即 API 級別 24 以上級別或 onResume()onStart() 生命週期方法 生命週期方法。對於位於 Service 中的玩家, 「onCreate()」中的準備工作

控製播放器

播放器準備就緒後,您可以透過呼叫方法控製播放 例如:

PlayerViewPlayerControlView 等 UI 元件會更新 當繫結至玩家時即可對應 ID。

放開播放器

播放時可能需要有限的資源 (例如影片) 因此,請務必呼叫 release() 以便釋出資源。

如果玩家位於 ActivityFragment,請釋放 API 級別 24 以上級別或 onPause()onStop() 生命週期方法 方法。對於位於 Service 中的玩家,您可以 onDestroy()發布新版本。

透過媒體工作階段管理播放

在 Android 上,媒體工作階段是與媒體互動的標準化方式 跨越程序邊界的玩家。將媒體工作階段連線至播放器 可讓您對外宣傳媒體播放,以及接收 來自外部來源的命令,例如與 適用於行動裝置和大型的系統媒體控制項 螢幕裝置。

如要使用媒體工作階段,請在 Media3 Session 模組中新增依附元件:

implementation "androidx.media3:media3-session:1.4.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 實作,包括 ExoPlayerCastPlayer 或 自訂實作方式

將控制權授予其他用戶端

用戶端應用程式可以實作媒體控制器 控制媒體工作階段的播放如要接收這些要求,請設定 callback 物件 建構 MediaSession

當控制器準備連線到媒體工作階段時, onConnect()敬上 方法。您可以使用 Google 提供的 ControllerInfo 決定是否要接受。 或拒絕 要求。如要查看範例,請參見 Media3 Session 試用版應用程式

連線後,控制器就能傳送播放指令給工作階段。 然後將這些指令委派給玩家。播放與播放清單 自動處理 Player 介面中定義的指令 會很有幫助

其他回呼方法可讓您處理 自訂播放指令 以及修改播放清單。這些回呼同樣包含 ControllerInfo 物件,因此您可以 可以依個別要求決定存取權控管機制

在背景播放媒體

舉例來說,在應用程式不在前景運作時,如要繼續播放媒體,例如: 播放音樂、有聲書或 Podcast,即使使用者沒有應用程式也沒問題 您的 PlayerMediaSession 應該封裝於 前景服務。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();
    }
}

在資訊清單中,Service 類別包含 MediaSessionService 意圖 篩選並要求 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 屬於不同的 Service,或 Fragment 會顯示玩家 UI 的位置,您可以使用 MediaController 來連結 在 ActivityFragmentonStart() 方法中, 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 不再移除時釋出元件 例如 ActivityonStop() 生命週期方法,方法是呼叫 MediaController.releaseFuture()

發布通知

需要使用前景服務才能發布通知。A 罩杯 MediaSessionService 會自動建立 以下使用者的 MediaStyle 通知: 格式為 MediaNotification。 如要提供自訂通知,請 MediaNotification.Provider敬上 合作對象:DefaultMediaNotificationProvider.Builder 或建立自訂實作供應商介面。新增 透過以下方式將供應商加到您的「MediaSession」: setMediaNotificationProvider

宣傳你的內容資料庫

MediaLibraryService 以允許用戶端在 MediaSessionService 上建構 ,藉此瀏覽應用程式提供的媒體內容。用戶端應用程式 MediaBrowser即可進行互動 這項資訊分享給您的MediaLibraryService

實作 MediaLibraryService 與實作 MediaSessionService,不過在 onGetSession() 中,您應該傳回 MediaLibrarySession 而不是 MediaSession。相較於 MediaSession.CallbackMediaLibrarySession.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 回呼 新增以下方法:

相關的回呼方法會包含 LibraryParams 包含用戶端應用程式的內容樹狀結構類型相關信號