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 Anwendungsfälle für die Wiedergabe abdecken, und das sich auf zusätzliche Anwendungsfälle anpassen lässt. ExoPlayer entfernt außerdem Geräte- und Betriebssystemfragmentierung, damit Ihr Code konsistent im gesamten Android-Ökosystem funktioniert. ExoPlayer umfasst:
- Unterstützung für Playlists
- Unterstützung einer Vielzahl von progressiven und adaptiven Streamingformaten
- Unterstützung für die clientseitige und serverseitige Anzeigenbereitstellung
- Unterstützung für die DRM-geschützte Wiedergabe
Auf dieser Seite werden Sie durch einige der wichtigsten Schritte beim Erstellen einer Wiedergabe-App geführt. Weitere Informationen finden Sie in unseren vollständigen Leitfäden zu Media3 ExoPlayer.
Erste Schritte
Fügen Sie zunächst eine Abhängigkeit vom ExoPlayer, der Benutzeroberfläche und den allgemeinen Modulen von Jetpack Media3 hinzu:
implementation "androidx.media3:media3-exoplayer:1.3.1" implementation "androidx.media3:media3-ui:1.3.1" implementation "androidx.media3:media3-common:1.3.1"
Je nach Anwendungsfall benötigst du möglicherweise auch zusätzliche Module von Media3, z. B. exoplayer-dash
, um Streams im DASH-Format wiederzugeben.
Ersetzen Sie 1.3.1
durch Ihre bevorzugte Version der Bibliothek. Die neueste Version finden Sie in den Versionshinweisen.
Mediaplayer erstellen
Bei Media3 können Sie entweder die enthaltene Implementierung der Player
-Schnittstelle (ExoPlayer
) verwenden oder Ihre eigene benutzerdefinierte Implementierung erstellen.
Erstellen eines ExoPlayers
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 Mediaplayer in der Lebenszyklusmethode onCreate()
des Speicherorts Activity
, Fragment
oder Service
erstellen.
Das Builder
bietet eine Reihe von Anpassungsoptionen, die für Sie interessant sein könnten, z. B.:
setAudioAttributes()
, um die Audiofokus-Handhabung zu konfigurierensetHandleAudioBecomingNoisy()
, um das Wiedergabeverhalten zu konfigurieren, wenn ein Audioausgabegerät getrennt istsetTrackSelector()
, um die Trackauswahl zu konfigurieren
Media3 bietet eine PlayerView
-UI-Komponente, die du in die Layoutdatei deiner App aufnehmen kannst. Diese Komponente enthält eine PlayerControlView
für Wiedergabesteuerung, eine SubtitleView
zum Anzeigen von Untertiteln und eine Surface
für das Rendern von Videos.
Player wird vorbereitet
Füge einer Playlist Medienelemente für die Wiedergabe mit Methoden wie setMediaItem()
und addMediaItem()
hinzu.
Rufen Sie dann prepare()
auf, um mit dem Laden von Medien zu beginnen und die erforderlichen Ressourcen abzurufen.
Sie sollten diese Schritte nicht ausführen, bevor die App im Vordergrund ausgeführt wird. Wenn sich Ihr Player in einem Activity
- oder Fragment
-Element befindet, bedeutet dies, dass er in der Lebenszyklusmethode onStart()
auf API-Level 24 und höher oder in der Lebenszyklusmethode onResume()
auf API-Ebene 23 und niedriger vorbereitet wird. Für einen Spieler in einem Service
können Sie ihn in onCreate()
vorbereiten.
Player steuern
Nachdem der Player vorbereitet wurde, können Sie die Wiedergabe steuern, indem Sie Methoden wie die folgenden aufrufen:
play()
undpause()
, um die Wiedergabe zu starten und zu pausierenseekTo()
sucht nach einer Position im aktuellen Medienelement- Mit
seekToNextMediaItem()
undseekToPreviousMediaItem()
kannst du durch die Playlist navigieren.
UI-Komponenten wie PlayerView
oder PlayerControlView
werden bei der Verknüpfung mit einem Spieler entsprechend aktualisiert.
Player loslassen
Für die Wiedergabe sind möglicherweise Ressourcen erforderlich, die nur begrenzt verfügbar sind, z. B. Video-Decoder. Daher ist es wichtig, release()
im Player aufzurufen, um Ressourcen freizugeben, wenn der Player nicht mehr benötigt wird.
Wenn sich Ihr Player in einem Activity
- oder Fragment
-Element befindet, geben Sie ihn über die Lebenszyklusmethode onStop()
auf API-Level 24 und höher oder die Methode onPause()
auf API-Ebene 23 und niedriger frei. Spieler, die sich in einem Service
befinden, können in onDestroy()
freigegeben werden.
Wiedergabe mit einer Mediensitzung verwalten
Unter Android bieten Mediensitzungen eine standardisierte Möglichkeit, mit einem Medienplayer über Prozessgrenzen hinweg zu interagieren. Wenn Sie eine Mediensitzung mit Ihrem Player verbinden, können Sie die Medienwiedergabe extern bewerben und Wiedergabebefehle von externen Quellen empfangen, z. B. zur Einbindung in Systemmediensteuerelemente auf Mobilgeräten und Geräten mit großen Bildschirmen.
Fügen Sie eine Abhängigkeit vom Modul „Media3 Session“ hinzu, um Mediensitzungen zu verwenden:
implementation "androidx.media3:media3-session:1.3.1"
Mediensitzung erstellen
So kannst du ein MediaSession
nach der Initialisierung eines Players erstellen:
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
. Dies funktioniert mit jeder Player
-Implementierung, einschließlich ExoPlayer
, CastPlayer
oder einer benutzerdefinierten Implementierung.
Anderen Clients Kontrolle gewähren
Client-Apps können einen Mediencontroller implementieren, um die Wiedergabe Ihrer Mediensitzung zu steuern. Damit du diese Anfragen erhalten kannst, musst du beim Erstellen des MediaSession
ein Callback-Objekt festlegen.
Wenn ein Controller eine Verbindung zu Ihrer Mediensitzung herstellt, wird die Methode onConnect()
aufgerufen. Mit dem angegebenen ControllerInfo
können Sie entscheiden, ob Sie die Anfrage annehmen oder ablehnen möchten. Ein Beispiel hierzu finden Sie in der Demo-App „Media3 Session“.
Sobald die Verbindung hergestellt ist, kann der Controller Wiedergabebefehle an die Sitzung senden. Die Sitzung delegiert diese Befehle dann an den Spieler. Die auf der Player
-Oberfläche definierten Wiedergabe- und Playlist-Befehle werden von der Sitzung automatisch ausgeführt.
Mit anderen Callback-Methoden können Sie z. B. Anfragen für benutzerdefinierte Wiedergabebefehle verarbeiten und die Playlist ändern. Diese Callbacks enthalten ebenfalls ein ControllerInfo
-Objekt, sodass Sie die Zugriffssteuerung für einzelne Anfragen festlegen können.
Medien im Hintergrund abspielen
Wenn Sie Medien auch dann abspielen möchten, wenn Ihre App nicht im Vordergrund ausgeführt wird und z. B. Musik, Hörbücher oder Podcasts abgespielt werden sollen, auch wenn der Nutzer die App nicht geöffnet hat, müssen Player
und MediaSession
in einem Dienst im Vordergrund gekapselt werden. Media3 stellt zu diesem Zweck die Schnittstelle MediaSessionService
bereit.
MediaSessionService
implementieren
Erstellen Sie eine Klasse, die MediaSessionService
erweitert, und instanziieren Sie MediaSession
in der Lebenszyklusmethode 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(); } }
Fügen Sie in Ihrem Manifest die Klasse Service
mit einem MediaSessionService
-Intent-Filter hinzu 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.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. Geben Sie MediaSession
zurück, um die Verbindungsanfrage anzunehmen, oder null
, um die Anfrage 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 UI herstellen
Da sich Ihre Mediensitzung nun in einem Service
befindet, das von der Activity
oder Fragment
getrennt ist, auf der sich die Benutzeroberfläche Ihres Players befindet, können Sie sie mithilfe eines MediaController
miteinander verknüpfen. Erstellen Sie in der Methode onStart()
von Activity
oder von Fragment
mit Ihrer UI einen SessionToken
für Ihre MediaSession
und verwenden Sie dann 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, sodass Sie die gleichen Methoden wie play()
und pause()
zur Steuerung der Wiedergabe verwenden können. Ähnlich wie bei anderen Komponenten sollten Sie die MediaController
freigeben, wenn sie nicht mehr benötigt wird (z. B. die Lebenszyklusmethode onStop()
eines Activity
), indem Sie MediaController.releaseFuture()
aufrufen.
Benachrichtigung veröffentlichen
Dienste im Vordergrund sind erforderlich, um eine Benachrichtigung zu veröffentlichen, während sie aktiv sind. Eine MediaSessionService
erstellt automatisch eine MediaStyle
-Benachrichtigung in Form einer MediaNotification
.
Wenn du eine benutzerdefinierte Benachrichtigung bereitstellen möchtest, musst du einen MediaNotification.Provider
mit DefaultMediaNotificationProvider.Builder
erstellen oder eine benutzerdefinierte Implementierung der Anbieterschnittstelle erstellen. Fügen Sie Ihren Anbieter mit setMediaNotificationProvider
zu MediaSession
hinzu.
Werbung für die Inhaltsbibliothek
Ein MediaLibraryService
baut auf einem MediaSessionService
auf, da es Clientanwendungen ermöglicht, die von Ihrer Anwendung bereitgestellten Medieninhalte zu durchsuchen. Client-Apps implementieren einen MediaBrowser
, um mit Ihrer MediaLibraryService
zu interagieren.
Die Implementierung von MediaLibraryService
ähnelt der Implementierung von MediaSessionService
, mit der Ausnahme, dass du in onGetSession()
anstelle von MediaSession
ein MediaLibrarySession
zurückgeben solltest. Im Vergleich zu MediaSession.Callback
enthält MediaLibrarySession.Callback
zusätzliche Methoden, mit denen ein Browserclient die von deinem Bibliotheksdienst angebotenen Inhalte aufrufen kann.
Deklarieren Sie ähnlich wie bei MediaSessionService
den 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 obige Beispiel enthält einen Intent-Filter sowohl für MediaLibraryService
als auch für die Abwärtskompatibilität für den alten MediaBrowserService
. Mit dem zusätzlichen Intent-Filter können Client-Apps, die die MediaBrowserCompat
API verwenden, Ihr Service
erkennen.
Mit einem MediaLibrarySession
können Sie Ihre Inhaltsbibliothek in einer Baumstruktur mit einem einzigen Stamm-MediaItem
bereitstellen. Jeder MediaItem
in der Baumstruktur kann eine beliebige Anzahl von untergeordneten MediaItem
-Knoten haben. Sie können je nach Anfrage der Clientanwendung einen anderen Stamm oder einen anderen Baum bereitstellen. Beispiel: Der Baum, den Sie an einen Client zurückgeben, der nach einer Liste mit empfohlenen Medienelementen sucht, kann nur den Stamm-MediaItem
und eine einzelne Ebene von untergeordneten MediaItem
-Knoten enthalten, während die Struktur, die Sie zu einer anderen Client-App zurückkehren, eine umfassendere Inhaltsbibliothek darstellen.
MediaLibrarySession
wird erstellt
Ein MediaLibrarySession
erweitert die MediaSession
API um Content Browsing APIs. Im Vergleich zum MediaSession
-Callback werden beim MediaLibrarySession
-Callback z. B. folgende Methoden hinzugefügt:
onGetLibraryRoot()
, wenn ein Client den StammMediaItem
eines Inhaltsbaums anfordertonGetChildren()
, wenn ein Client die untergeordneten Elemente vonMediaItem
im Inhaltsbaum anfordertonGetSearchResult()
, wenn ein Client Suchergebnisse aus dem Inhaltsbaum für eine bestimmte Abfrage anfordert
Relevante Callback-Methoden umfassen ein LibraryParams
-Objekt mit zusätzlichen Signalen zur Art der Inhaltsstruktur, an der eine Client-App interessiert ist.