Jetpack Media3 definiert eine Player
-Schnittstelle, die grundlegende Funktionen für die Wiedergabe von Video- und Audiodateien beschreibt. ExoPlayer
ist die Standardimplementierung dieser Schnittstelle in Media3. Wir empfehlen die Verwendung von ExoPlayer, da es eine umfassende Reihe von Funktionen bietet, die die meisten Wiedergabeanwendungsfälle abdecken, und an alle zusätzlichen Anwendungsfälle angepasst werden kann. ExoPlayer abstrahiert auch die Geräte- und Betriebssystemfragmentierung, sodass Ihr Code im gesamten Android-Ökosystem konsistent funktioniert. ExoPlayer umfasst:
- Unterstützung von Playlists
- Unterstützung für verschiedene progressive und adaptive Streaming-Formate
- Unterstützung der Anzeigenbereitstellung sowohl auf Client- als auch auf Serverseite
- Unterstützung für die Wiedergabe von DRM-geschützten Inhalten
Auf dieser Seite werden einige der wichtigsten Schritte beim Erstellen einer Wiedergabe-App beschrieben. Weitere Informationen finden Sie in unseren vollständigen Anleitungen zu Media3 ExoPlayer.
Erste Schritte
Fügen Sie zuerst eine Abhängigkeit von den ExoPlayer-, UI- und Common-Modulen von Jetpack Media3 hinzu:
implementation "androidx.media3:media3-exoplayer:1.7.1" implementation "androidx.media3:media3-ui:1.7.1" implementation "androidx.media3:media3-common:1.7.1"
Je nach Anwendungsfall benötigen Sie möglicherweise auch zusätzliche Module aus Media3, z. B. exoplayer-dash
, um Streams im DASH-Format abzuspielen.
Ersetzen Sie 1.7.1
durch die gewünschte Version der Bibliothek. Die aktuelle Version finden Sie in den Versionshinweisen.
Mediaplayer erstellen
Mit Media3 können Sie entweder die enthaltene Implementierung der Player
-Schnittstelle, ExoPlayer
, verwenden oder eine eigene benutzerdefinierte Implementierung erstellen.
ExoPlayer erstellen
Die einfachste Methode zum Erstellen einer ExoPlayer
-Instanz ist folgende:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Sie können Ihren Media Player in der Methode onCreate()
des Lebenszyklus der Activity
, Fragment
oder Service
erstellen, in der er sich befindet.
Die Builder
bietet eine Reihe von Anpassungsoptionen, die für Sie interessant sein könnten, z. B.:
setAudioAttributes()
zum Konfigurieren der Verarbeitung des AudiofokussetHandleAudioBecomingNoisy()
um das Wiedergabeverhalten zu konfigurieren, wenn ein Audioausgabegerät getrennt wirdsetTrackSelector()
zum Konfigurieren der Track-Auswahl
Media3 bietet eine PlayerView
-UI-Komponente, die Sie in die Layoutdatei Ihrer App einfügen können. Diese Komponente umfasst ein PlayerControlView
für die Wiedergabesteuerung, ein SubtitleView
für die Anzeige von Untertiteln und ein Surface
für das Rendern von Videos.
Player vorbereiten
Füge einer Playlist Mediendateien für die Wiedergabe mit Methoden wie setMediaItem()
und addMediaItem()
hinzu.
Rufen Sie dann prepare()
auf, um mit dem Laden von Media zu beginnen und die erforderlichen Ressourcen abzurufen.
Sie sollten diese Schritte erst ausführen, wenn die App im Vordergrund ist. Wenn sich dein Player in einem Activity
oder Fragment
befindet, bedeutet das, dass der Player in der onStart()
-Lebenszyklusmethode auf API-Level 24 und höher oder in der onResume()
-Lebenszyklusmethode auf API-Level 23 und niedriger vorbereitet wird. Für einen Spieler, der sich in einem Service
befindet, können Sie ihn in onCreate()
vorbereiten.
Player steuern
Nachdem der Player vorbereitet wurde, können Sie die Wiedergabe steuern, indem Sie Methoden für den Player aufrufen, z. B.:
play()
undpause()
zum Starten und Pausieren der WiedergabeseekTo()
, um zu einer Position innerhalb des aktuellen Media-Elements zu springenseekToNextMediaItem()
undseekToPreviousMediaItem()
zum Navigieren in der Playlist
UI-Komponenten wie PlayerView
oder PlayerControlView
werden entsprechend aktualisiert, wenn sie an einen Player gebunden sind.
Spieler freigeben
Die Wiedergabe kann Ressourcen erfordern, die nur begrenzt verfügbar sind, z. B. Videodecoder. Daher ist es wichtig, release()
für den Player aufzurufen, um Ressourcen freizugeben, wenn der Player nicht mehr benötigt wird.
Wenn sich der Player in einem Activity
oder Fragment
befindet, geben Sie ihn mit der onStop()
-Lebenszyklusmethode auf API-Level 24 und höher oder mit der onPause()
-Methode auf API-Level 23 und niedriger frei. Ein Spieler, der sich in einem Service
befindet, kann in onDestroy()
veröffentlicht werden.
Wiedergabe mit einer Mediensitzung verwalten
Unter Android bieten Mediensitzungen eine standardisierte Möglichkeit, prozessübergreifend mit einem Mediaplayer zu interagieren. Wenn Sie eine Mediensitzung mit Ihrem Player verbinden, können Sie Ihre Medienwiedergabe extern bewerben und Wiedergabebefehle von externen Quellen empfangen, z. B. um die System-Mediensteuerung auf Mobilgeräten und Großbildgeräten zu integrieren.
Wenn Sie Mediensitzungen verwenden möchten, fügen Sie eine Abhängigkeit vom Media3-Sitzungsmodul hinzu:
implementation "androidx.media3:media3-session:1.7.1"
Mediensitzung erstellen
So erstellen Sie ein MediaSession
-Objekt nach der Initialisierung eines Players:
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 synchronisiert den Status von Player
automatisch mit dem Status von MediaSession
. Das funktioniert mit jeder Player
-Implementierung, einschließlich ExoPlayer
, CastPlayer
oder einer benutzerdefinierten Implementierung.
Anderen Kunden die Kontrolle überlassen
Client-Apps können einen Mediencontroller implementieren, um die Wiedergabe Ihrer Mediensitzung zu steuern. Wenn Sie diese Anfragen erhalten möchten, legen Sie beim Erstellen von MediaSession
ein Callback-Objekt fest.
Wenn ein Controller eine Verbindung zu Ihrer Mediensitzung herstellt, wird die Methode onConnect()
aufgerufen. Anhand der bereitgestellten ControllerInfo
können Sie entscheiden, ob Sie die Anfrage annehmen oder ablehnen. Ein Beispiel dafür finden Sie in der Media3 Session-Demo-App.
Sobald eine Verbindung hergestellt ist, kann ein Controller Wiedergabebefehle an die Sitzung senden. Die Sitzung delegiert diese Befehle dann an den Player. Wiedergabe- und Playlist-Befehle, die in der Player
-Schnittstelle definiert sind, werden automatisch von der Sitzung verarbeitet.
Mit anderen Callback-Methoden können Sie beispielsweise Anfragen für benutzerdefinierte Wiedergabebefehle und Änderungen an der Playlist verarbeiten. Diese Callbacks enthalten ebenfalls ein ControllerInfo
-Objekt, sodass Sie die Zugriffssteuerung für jede Anfrage einzeln festlegen können.
Medien im Hintergrund abspielen
Wenn Sie Medien weiter abspielen möchten, wenn Ihre App nicht im Vordergrund ist, z. B. um Musik, Hörbücher oder Podcasts abzuspielen, auch wenn der Nutzer Ihre App nicht geöffnet hat, sollten Ihre Player
und MediaSession
in einem Dienst im Vordergrund gekapselt werden. Media3 bietet dafür die MediaSessionService
-Schnittstelle.
MediaSessionService
implementieren
Erstellen Sie eine Klasse, die MediaSessionService
erweitert, und instanziieren Sie MediaSession
in der Lifecycle-Methode 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(); } }
Geben Sie in Ihrem Manifest die Klasse Service
mit einem Intent-Filter MediaSessionService
an und fordern Sie die Berechtigung FOREGROUND_SERVICE
an, um einen Vordergrunddienst auszuführen:
<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" />
Überschreiben Sie schließlich in der von Ihnen erstellten Klasse die Methode onGetSession()
, um den Clientzugriff auf Ihre Mediensitzung zu steuern. Gib MediaSession
zurück, um die Verbindungsanfrage anzunehmen, oder null
, um sie abzulehnen.
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; }
Verbindung zur Benutzeroberfläche herstellen
Da sich Ihre Mediensitzung jetzt in einem Service
befindet, das sich von Activity
oder Fragment
unterscheidet, in dem sich die Benutzeroberfläche Ihres Players befindet, können Sie ein MediaController
verwenden, um sie zu verknüpfen. Erstellen Sie in der Methode onStart()
der Activity
oder Fragment
mit Ihrer Benutzeroberfläche einen SessionToken
für Ihren MediaSession
und verwenden Sie dann den SessionToken
, um einen MediaController
zu erstellen. Das Erstellen eines MediaController
erfolgt asynchron.
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
implementiert die Player
-Schnittstelle. Sie können also dieselben Methoden wie play()
und pause()
verwenden, um die Wiedergabe zu steuern. Wie bei anderen Komponenten sollten Sie die MediaController
freigeben, wenn sie nicht mehr benötigt wird, z. B. in der onStop()
-Lifecycle-Methode eines Activity
, indem Sie MediaController.releaseFuture()
aufrufen.
Benachrichtigung veröffentlichen
Für Dienste im Vordergrund ist es erforderlich, dass sie eine Benachrichtigung veröffentlichen, während sie aktiv sind. Bei einer MediaSessionService
wird automatisch eine MediaStyle
-Benachrichtigung in Form einer MediaNotification
erstellt.
Wenn Sie eine benutzerdefinierte Benachrichtigung bereitstellen möchten, erstellen Sie ein MediaNotification.Provider
mit DefaultMediaNotificationProvider.Builder
oder erstellen Sie eine benutzerdefinierte Implementierung der Anbieterschnittstelle. Fügen Sie Ihren Anbieter mit setMediaNotificationProvider
zu Ihrem MediaSession
hinzu.
Werbung für Ihre Inhaltsbibliothek
Eine MediaLibraryService
baut auf einer MediaSessionService
auf, indem Client-Apps die von Ihrer App bereitgestellten Medieninhalte durchsuchen können. Client-Apps implementieren eine MediaBrowser
, um mit Ihrer MediaLibraryService
zu interagieren.
Die Implementierung von MediaLibraryService
ähnelt der Implementierung von MediaSessionService
. Der Unterschied besteht darin, dass Sie in onGetSession()
ein MediaLibrarySession
anstelle eines MediaSession
zurückgeben sollten. Im Vergleich zu einem MediaSession.Callback
enthält das MediaLibrarySession.Callback
zusätzliche Methoden, mit denen ein Browserclient die von Ihrem Bibliotheksdienst angebotenen Inhalte durchsuchen kann.
Deklarieren Sie wie bei MediaSessionService
die MediaLibraryService
in Ihrem Manifest und fordern Sie die Berechtigung FOREGROUND_SERVICE
an, um einen Dienst im Vordergrund auszuführen:
<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" />
Das Beispiel oben enthält einen Intent-Filter für MediaLibraryService
und zur Abwärtskompatibilität auch für das alte MediaBrowserService
. Der zusätzliche Intent-Filter ermöglicht es Client-Apps, die die MediaBrowserCompat
API verwenden, Ihre Service
zu erkennen.
Mit einem MediaLibrarySession
können Sie Ihre Inhaltsbibliothek in einer Baumstruktur mit einem einzelnen Stammverzeichnis MediaItem
bereitstellen. Jedes MediaItem
im Baum kann beliebig viele untergeordnete MediaItem
-Knoten haben. Sie können je nach Anfrage der Client-App einen anderen Stamm oder eine andere Struktur bereitstellen. Der Baum, den Sie an einen Client zurückgeben, der eine Liste empfohlener Media-Elemente sucht, enthält möglicherweise nur den Stammknoten MediaItem
und eine einzelne Ebene mit untergeordneten MediaItem
-Knoten. Der Baum, den Sie an eine andere Client-App zurückgeben, kann dagegen eine vollständigere Inhaltsbibliothek darstellen.
MediaLibrarySession
erstellen
Eine MediaLibrarySession
erweitert die MediaSession
API um APIs zum Durchsuchen von Inhalten. Im Vergleich zum MediaSession
-Callback werden dem MediaLibrarySession
-Callback Methoden wie die folgenden hinzugefügt:
onGetLibraryRoot()
wenn ein Client den StammMediaItem
eines Inhaltsbaums anfordertonGetChildren()
wenn ein Client die untergeordneten Elemente vonMediaItem
im Inhaltsbaum anfordertonGetSearchResult()
wenn ein Kunde Suchergebnisse aus dem Inhaltsbaum für eine bestimmte Anfrage anfordert
Relevante Callback-Methoden enthalten ein LibraryParams
-Objekt mit zusätzlichen Signalen zum Typ des Inhaltsbaums, für den sich eine Client-App interessiert.