Jetpack Media3 definiuje interfejs Player
, który określa podstawowe funkcje odtwarzania plików wideo i audio. ExoPlayer
to domyślna implementacja tego interfejsu w Media3. Zalecamy korzystanie z ExoPlayera, ponieważ zapewnia on kompleksowy zestaw funkcji, które obejmują większość przypadków użycia odtwarzania, i można go dostosować do obsługi dodatkowych przypadków użycia. ExoPlayer eliminuje też fragmentację urządzeń i systemów operacyjnych, dzięki czemu Twój kod działa spójnie w całym ekosystemie Androida. ExoPlayer obejmuje:
- Obsługa playlist
- Obsługa różnych formatów strumieniowania progresywnego i adaptacyjnego
- Obsługa wstawiania reklam po stronie klienta i po stronie serwera
- Obsługa odtwarzania treści chronionych DRM
Na tej stronie znajdziesz opis najważniejszych kroków tworzenia aplikacji do odtwarzania. Więcej informacji znajdziesz w naszych pełnych przewodnikach po Media3 ExoPlayer.
Pierwsze kroki
Aby rozpocząć, dodaj zależność od modułów ExoPlayer, UI i Common biblioteki Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.7.1" implementation "androidx.media3:media3-ui:1.7.1" implementation "androidx.media3:media3-common:1.7.1"
W zależności od przypadku użycia możesz też potrzebować dodatkowych modułów z Media3, np. exoplayer-dash
, aby odtwarzać strumienie w formacie DASH.
Zastąp 1.7.1
preferowaną wersją biblioteki. Najnowszą wersję znajdziesz w informacjach o wersji.
Tworzenie odtwarzacza multimediów
W Media3 możesz użyć dołączonej implementacji interfejsu Player
ExoPlayer
lub utworzyć własną implementację niestandardową.
Tworzenie ExoPlayera
Najprostszy sposób utworzenia instancji ExoPlayer
jest następujący:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Odtwarzacz multimediów możesz utworzyć w metodzie cyklu życia onCreate()
elementu Activity
, Fragment
lub Service
, w którym się znajduje.
Builder
obejmuje szereg opcji dostosowywania, które mogą Cię zainteresować, takich jak:
setAudioAttributes()
aby skonfigurować obsługę aktywności audio.setHandleAudioBecomingNoisy()
aby skonfigurować sposób odtwarzania po odłączeniu urządzenia wyjściowego audio.setTrackSelector()
aby skonfigurować wybór ścieżki
Media3 udostępnia PlayerView
komponent interfejsu, który możesz uwzględnić w pliku układu aplikacji. Ten komponent zawiera PlayerControlView
do sterowania odtwarzaniem, SubtitleView
do wyświetlania napisów i Surface
do renderowania wideo.
Przygotowywanie odtwarzacza
Dodaj elementy multimedialne do playlisty, aby odtwarzać je za pomocą metod takich jak setMediaItem()
i addMediaItem()
.
Następnie wywołaj funkcję prepare()
, aby rozpocząć wczytywanie multimediów i uzyskać niezbędne zasoby.
Nie wykonuj tych czynności, zanim aplikacja nie będzie działać na pierwszym planie. Jeśli odtwarzacz znajduje się w stanie Activity
lub Fragment
, oznacza to przygotowanie odtwarzacza w metodzie cyklu życia onStart()
na poziomie interfejsu API 24 lub wyższym albo w metodzie cyklu życia onResume()
na poziomie interfejsu API 23 lub niższym. W przypadku odtwarzacza, który znajduje się w Service
, możesz przygotować go w onCreate()
.
Sterowanie odtwarzaczem
Po przygotowaniu odtwarzacza możesz sterować odtwarzaniem, wywołując w nim metody, takie jak:
play()
ipause()
aby rozpocząć i wstrzymać odtwarzanie.seekTo()
– przejście do pozycji w bieżącym elemencie multimedialnymseekToNextMediaItem()
iseekToPreviousMediaItem()
, aby poruszać się po playliście.
Komponenty interfejsu, takie jak PlayerView
lub PlayerControlView
, będą odpowiednio aktualizowane po powiązaniu z odtwarzaczem.
Zwolnij gracza
Odtwarzanie może wymagać zasobów, które są dostępne w ograniczonej ilości, np. dekoderów wideo, dlatego ważne jest, aby wywoływać metodę release()
w odtwarzaczu, aby zwolnić zasoby, gdy nie jest on już potrzebny.
Jeśli odtwarzacz jest w stanie Activity
lub Fragment
, zwolnij go w metodzie cyklu życia onStop()
na poziomie interfejsu API 24 lub wyższym albo w metodzie onPause()
na poziomie interfejsu API 23 lub niższym. Gracza, który jest w Service
, możesz zwolnić w onDestroy()
.
Zarządzanie odtwarzaniem za pomocą sesji multimedialnej
Na Androidzie sesje multimedialne zapewniają standardowy sposób interakcji z odtwarzaczem multimediów w różnych procesach. Połączenie sesji multimedialnej z odtwarzaczem umożliwia reklamowanie odtwarzania multimediów na zewnątrz i otrzymywanie poleceń odtwarzania ze źródeł zewnętrznych, np. w celu integracji z systemowymi elementami sterującymi multimediami na urządzeniach mobilnych i urządzeniach z dużym ekranem.
Aby korzystać z sesji multimediów, dodaj zależność od modułu sesji Media3:
implementation "androidx.media3:media3-session:1.7.1"
Tworzenie sesji multimedialnej
Po zainicjowaniu odtwarzacza możesz utworzyć MediaSession
w ten sposób:
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 automatycznie synchronizuje stan Player
ze stanem MediaSession
. Działa to w przypadku każdej implementacji Player
, w tym ExoPlayer
, CastPlayer
i implementacji niestandardowej.
Przyznawanie kontroli innym klientom
Aplikacje klienckie mogą wdrożyć kontroler multimediów, aby sterować odtwarzaniem sesji multimedialnej. Aby otrzymywać te prośby, podczas tworzenia obiektu MediaSession
ustaw obiekt callback.
Gdy kontroler ma się połączyć z sesją multimedialną, wywoływana jest metoda
onConnect()
. Na podstawie podanych ControllerInfo
możesz zaakceptować lub odrzucić prośbę. Przykład znajdziesz w aplikacji demonstracyjnej sesji Media3.
Po nawiązaniu połączenia kontroler może wysyłać do sesji polecenia odtwarzania. Sesja przekazuje te polecenia do odtwarzacza. Polecenia odtwarzania i playlisty zdefiniowane w interfejsie Player
są automatycznie obsługiwane przez sesję.
Inne metody wywołania zwrotnego umożliwiają obsługę np. żądań niestandardowych poleceń odtwarzania i modyfikowania playlisty. Te wywołania zwrotne również zawierają obiekt ControllerInfo
, dzięki czemu możesz określać kontrolę dostępu dla poszczególnych żądań.
Odtwarzanie multimediów w tle
Aby odtwarzać multimedia, gdy aplikacja nie jest na pierwszym planie, np. odtwarzać muzykę, audiobooki lub podcasty, nawet gdy użytkownik nie ma otwartej aplikacji, Player
i MediaSession
powinny być umieszczone w usłudze na pierwszym planie. Media3 udostępnia w tym celu interfejs MediaSessionService
.
Wdrażanie MediaSessionService
Utwórz klasę, która rozszerza MediaSessionService
, i utwórz instancję MediaSession
w metodzie cyklu życia onCreate()
.
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(); } }
W pliku manifestu zdefiniuj klasę Service
z filtrem intencji MediaSessionService
i poproś o uprawnienie FOREGROUND_SERVICE
do uruchamiania usługi na pierwszym planie:
<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" />
Na koniec w utworzonej klasie zastąp metodę onGetSession()
, aby kontrolować dostęp klienta do sesji multimedialnej. Wpisz MediaSession
, aby zaakceptować prośbę o połączenie, lub null
, aby ją odrzucić.
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; }
Łączenie z interfejsem
Teraz, gdy sesja multimedialna jest Service
oddzielona od Activity
lub Fragment
, w którym znajduje się interfejs odtwarzacza, możesz użyć MediaController
, aby je połączyć. W metodzie onStart()
interfejsu Activity
lub Fragment
utwórz SessionToken
dla MediaSession
, a potem użyj SessionToken
, aby utworzyć MediaController
. Tworzenie MediaController
odbywa się asynchronicznie.
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
implementuje interfejs Player
, więc możesz używać tych samych metod, takich jak play()
i pause()
, do sterowania odtwarzaniem. Podobnie jak w przypadku innych komponentów, pamiętaj, aby zwolnić MediaController
, gdy nie jest już potrzebny, np. w metodzie cyklu życia onStop()
elementu Activity
, wywołując MediaController.releaseFuture()
.
Publikowanie powiadomienia
Usługi na pierwszym planie są wymagane do publikowania powiadomień, gdy są aktywne. A
MediaSessionService
automatycznie utworzy dla Ciebie MediaStyle
powiadomienie w formie MediaNotification
.
Aby wyświetlić niestandardowe powiadomienie, utwórz element MediaNotification.Provider
z elementem DefaultMediaNotificationProvider.Builder
lub utwórz niestandardową implementację interfejsu dostawcy. Dodaj dostawcę do MediaSession
za pomocą setMediaNotificationProvider
.
Reklamowanie biblioteki treści
MediaLibraryService
jest rozszerzeniem MediaSessionService
, które umożliwia aplikacjom klienckim przeglądanie treści multimedialnych udostępnianych przez Twoją aplikację. Aplikacje klienckie implementują MediaBrowser
, aby wchodzić w interakcję z MediaLibraryService
.
Wdrażanie MediaLibraryService
jest podobne do wdrażania MediaSessionService
, z tą różnicą, że w onGetSession()
należy zwracać MediaLibrarySession
zamiast MediaSession
. W porównaniu z MediaSession.Callback
interfejs MediaLibrarySession.Callback
zawiera dodatkowe metody, które umożliwiają klientowi przeglądarki poruszanie się po treściach oferowanych przez usługę biblioteki.
Podobnie jak w przypadku MediaSessionService
, zadeklaruj MediaLibraryService
w pliku manifestu i poproś o uprawnienie FOREGROUND_SERVICE
do uruchamiania usługi na pierwszym planie:
<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" />
Powyższy przykład zawiera filtr intencji zarówno dla MediaLibraryService
, jak i – na potrzeby zgodności wstecznej – starszego MediaBrowserService
. Dodatkowy filtr intencji umożliwia aplikacjom klienckim korzystającym z interfejsu MediaBrowserCompat
API rozpoznawanie Twojego urządzenia Service
.
MediaLibrarySession
umożliwia wyświetlanie biblioteki treści w strukturze drzewa z jednym węzłem głównym MediaItem
. Każdy węzeł MediaItem
w drzewie może mieć dowolną liczbę węzłów podrzędnych MediaItem
. Możesz wyświetlać inny węzeł główny lub inne drzewo w zależności od żądania aplikacji klienckiej. Na przykład drzewo, które zwracasz klientowi szukającemu listy polecanych multimediów, może zawierać tylko węzeł główny MediaItem
i jeden poziom węzłów podrzędnych MediaItem
, podczas gdy drzewo zwracane do innej aplikacji klienta może reprezentować bardziej kompletną bibliotekę treści.
Tworzenie MediaLibrarySession
MediaLibrarySession
rozszerza interfejs MediaSession
API, aby dodać interfejsy API do przeglądania treści. W porównaniu z MediaSession
wywołaniem zwrotnym MediaLibrarySession
wywołanie zwrotne dodaje takie metody jak:
onGetLibraryRoot()
gdy klient prosi oMediaItem
korzeń drzewa treści;onGetChildren()
gdy klient zażąda elementów podrzędnych węzłaMediaItem
w drzewie treści.onGetSearchResult()
gdy klient prosi o wyniki wyszukiwania z drzewa treści dla danego zapytania;
Odpowiednie metody wywołania zwrotnego będą zawierać obiekt LibraryParams
z dodatkowymi sygnałami dotyczącymi typu drzewa treści, którym jest zainteresowana aplikacja kliencka.