Często dobrze jest odtwarzać multimedia, gdy aplikacja nie działa na pierwszym planie. Dla: Odtwarzacz muzyki zwykle odtwarza treści tylko wtedy, gdy użytkownik jest zablokowany z jego urządzenia lub korzysta z innej aplikacji. Biblioteka Media3 zawiera szereg funkcji które umożliwiają odtwarzanie w tle.
Korzystanie z MediaSessionService
Aby włączyć odtwarzanie w tle, pliki Player
i
MediaSession
w osobnej Usłudze.
Dzięki temu urządzenie może wyświetlać multimedia nawet wtedy, gdy aplikacja nie jest zainstalowana
na pierwszym planie.
Podczas hostowania odtwarzacza w ramach Usługi należy użyć MediaSessionService
.
Aby to zrobić, utwórz klasę, która rozszerza klasę MediaSessionService
, i w jej ramach utwórz sesję multimediów.
Użycie MediaSessionService
umożliwia klientom zewnętrznym, takim jak Google.
z Asystentem, systemem sterowania multimediami w systemie lub na urządzeniach towarzyszących, takich jak Wear OS
połączyć się z nią i sterować odtwarzaniem, a wszystko to bez dostępu do
ani działań związanych z interfejsem aplikacji. W tym samym czasie do tego samego MediaSessionService
może być podłączonych kilka aplikacji klienta, z których każda ma swój własny MediaController
.
Wdrażanie cyklu życia usługi
Musisz zaimplementować 3 metody cyklu życia usługi:
- Funkcja
onCreate()
jest wywoływana, gdy ma się połączyć pierwszy kontroler. została utworzona i uruchomiona usługa. To najlepsze miejsce do tworzeniaPlayer
iMediaSession
. onTaskRemoved(Intent)
jest wywoływany, gdy użytkownik zamknie aplikację z ostatnich zadań. Jeśli odtwarzanie jest w toku, aplikacja może zachować usługę który działa na pierwszym planie. Jeśli odtwarzacz jest wstrzymany, usługa nie jest na pierwszym planie i trzeba ją zatrzymać.- Funkcja
onDestroy()
jest wywoływana podczas zatrzymywania usługi. Wszystkie zasoby w tym odtwarzacz i sesję.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your player and media session in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // The user dismissed the app from the recent tasks override fun onTaskRemoved(rootIntent: Intent?) { val player = mediaSession?.player!! if (!player.playWhenReady || player.mediaItemCount == 0 || player.playbackState == Player.STATE_ENDED) { // Stop the service if not playing, continue playing in the background // otherwise. stopSelf() } } // 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; // Create your Player and MediaSession in the onCreate lifecycle event @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } // The user dismissed the app from the recent tasks @Override public void onTaskRemoved(@Nullable Intent rootIntent) { Player player = mediaSession.getPlayer(); if (!player.getPlayWhenReady() || player.getMediaItemCount() == 0 || player.getPlaybackState() == Player.STATE_ENDED) { // Stop the service if not playing, continue playing in the background // otherwise. stopSelf(); } } // Remember to release the player and media session in onDestroy @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
Zamiast kontynuować odtwarzanie w tle, aplikacja może w każdym przypadku zatrzymać usługę, gdy użytkownik ją zamknie:
Kotlin
override fun onTaskRemoved(rootIntent: Intent?) { val player = mediaSession.player if (player.playWhenReady) { // Make sure the service is not in foreground. player.pause() } stopSelf() }
Java
@Override public void onTaskRemoved(@Nullable Intent rootIntent) { Player player = mediaSession.getPlayer(); if (player.getPlayWhenReady()) { // Make sure the service is not in foreground. player.pause(); } stopSelf(); }
Przyznawanie dostępu do sesji multimediów
Zastąpić metodę onGetSession()
, aby umożliwić innym klientom dostęp do sesji multimediów utworzonej podczas tworzenia usługi.
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // [...] lifecycle methods omitted override fun onGetSession(controllerInfo: MediaSession.ControllerInfo): MediaSession? = mediaSession }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; // [...] lifecycle methods omitted @Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { return mediaSession; } }
Zadeklaruj usługę w pliku manifestu
Aplikacja wymaga uprawnień do uruchomienia usługi na pierwszym planie. Dodaj parametr
FOREGROUND_SERVICE
do pliku manifestu, a jeśli kierujesz reklamy na interfejs API 34
powyżej także FOREGROUND_SERVICE_MEDIA_PLAYBACK
:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
Musisz też zadeklarować klasę Service
w pliku manifestu za pomocą filtra intencji
z MediaSessionService
.
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
Musisz zdefiniować foregroundServiceType
, który obejmuje mediaPlayback
, gdy aplikacja działa na urządzeniu z Androidem 10 (poziom interfejsu API 29) lub nowszym.
sterować odtwarzaniem za pomocą MediaController
,
W aktywności lub fragmencie zawierającym interfejs użytkownika odtwarzacza możesz utworzyć link między interfejsem a sesją multimediów za pomocą elementu MediaController
. Twój interfejs użytkownika używa sterownika multimediów, aby wysyłać polecenia z interfejsu do odtwarzacza w trakcie sesji. Szczegółowe informacje o tworzeniu i używaniu MediaController
znajdziesz w przewodniku Tworzenie MediaController
.
Obsługa poleceń interfejsu
Urządzenie MediaSession
otrzymuje polecenia od kontrolera za pomocą interfejsu MediaSession.Callback
. Inicjowanie MediaSession
tworzy domyślną implementację MediaSession.Callback
, która automatycznie obsługuje wszystkie polecenia wysyłane przez MediaController
do odtwarzacza.
Powiadomienie
MediaSessionService
automatycznie tworzy dla Ciebie MediaNotification
, który powinien działać w większości przypadków. Opublikowane powiadomienie jest domyślnie
MediaStyle
powiadomienie
który jest zawsze na bieżąco
z sesji multimediów i wyświetlają elementy sterujące odtwarzaniem. MediaNotification
jest świadomy Twojej sesji i może służyć do sterowania odtwarzaniem w innych aplikacjach, które są połączone z tą samą sesją.
Na przykład aplikacja do strumieniowego odtwarzania muzyki korzystająca z elementu MediaSessionService
utworzy element MediaNotification
, który wyświetla tytuł, wykonawcę i okładkę albumu dla aktualnie odtwarzanego elementu multimedialnego wraz z elementami sterującymi odtwarzaniem na podstawie konfiguracji elementu MediaSession
.
Wymagane metadane można podać w multimediów lub zadeklarować jako część elementu multimediów, jak w tym fragmencie kodu:
Kotlin
val mediaItem = MediaItem.Builder() .setMediaId("media-1") .setUri(mediaUri) .setMediaMetadata( MediaMetadata.Builder() .setArtist("David Bowie") .setTitle("Heroes") .setArtworkUri(artworkUri) .build() ) .build() mediaController.setMediaItem(mediaItem) mediaController.prepare() mediaController.play()
Java
MediaItem mediaItem = new MediaItem.Builder() .setMediaId("media-1") .setUri(mediaUri) .setMediaMetadata( new MediaMetadata.Builder() .setArtist("David Bowie") .setTitle("Heroes") .setArtworkUri(artworkUri) .build()) .build(); mediaController.setMediaItem(mediaItem); mediaController.prepare(); mediaController.play();
Aplikacje mogą dostosować przyciski poleceń w elementach sterujących Android Media. Więcej informacji o dostosowywaniu elementów sterujących Android Media
Personalizacja powiadomień
Aby dostosować powiadomienie, utwórz MediaNotification.Provider
za pomocą DefaultMediaNotificationProvider.Builder
lub stwórz niestandardową implementację interfejsu dostawcy. Dodaj:
operatora sieci MediaSessionService
za pomocą
setMediaNotificationProvider
Wznowienie odtwarzania
Przyciski multimedialne to przyciski sprzętowe dostępne na urządzeniach z Androidem i innych urządzeniach peryferyjnych, np. przycisk odtwarzania lub pauzy na słuchawkach Bluetooth. Multimedia3 obsługuje wejściowe przyciski multimediów, gdy usługa jest uruchomiona.
Zadeklaruj odbiornik przycisku multimediów Media3
Media3 udostępnia interfejs API, który umożliwia użytkownikom wznowienie pracy.
odtwarzania po zakończeniu działania aplikacji, nawet po wyłączeniu urządzenia.
Zrestartowano. Domyślnie wznawianie odtwarzania jest wyłączone. Oznacza to, że użytkownik nie może wznowić odtwarzania, gdy usługa nie działa. Aby wyrazić zgodę, zacznij od
zadeklaruj pole MediaButtonReceiver
w pliku manifestu:
<receiver android:name="androidx.media3.session.MediaButtonReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
Wdrażanie wywołania zwrotnego wznowienia odtwarzania
Gdy urządzenie Bluetooth lub
funkcja wznowienia interfejsu systemu Android,
onPlaybackResumption()
metoda wywołania zwrotnego.
Kotlin
override fun onPlaybackResumption( mediaSession: MediaSession, controller: ControllerInfo ): ListenableFuture<MediaItemsWithStartPosition> { val settable = SettableFuture.create<MediaItemsWithStartPosition>() scope.launch { // Your app is responsible for storing the playlist and the start position // to use here val resumptionPlaylist = restorePlaylist() settable.set(resumptionPlaylist) } return settable }
Java
@Override public ListenableFuture<MediaItemsWithStartPosition> onPlaybackResumption( MediaSession mediaSession, ControllerInfo controller ) { SettableFuture<MediaItemsWithStartPosition> settableFuture = SettableFuture.create(); settableFuture.addListener(() -> { // Your app is responsible for storing the playlist and the start position // to use here MediaItemsWithStartPosition resumptionPlaylist = restorePlaylist(); settableFuture.set(resumptionPlaylist); }, MoreExecutors.directExecutor()); return settableFuture; }
Jeśli masz zapisane inne parametry, takie jak szybkość odtwarzania, tryb powtarzania czy losowy, onPlaybackResumption()
to dobre miejsce na skonfigurowanie odtwarzacza za pomocą tych parametrów, zanim Media3 przygotuje odtwarzacz i rozpocznie odtwarzanie po zakończeniu wywołania zwrotnego.
Zaawansowana konfiguracja kontrolera i zgodność wsteczna
Typowym scenariuszem jest użycie MediaController
w interfejsie aplikacji do sterowania odtwarzaniem i wyświetlania playlisty. Jednocześnie sesja jest udostępniana
do klientów zewnętrznych, takich jak elementy sterujące multimediami na Androidzie i Asystenta na urządzeniach mobilnych lub telewizorach,
Wear OS na zegarkach i Androida Auto w samochodach. Aplikacja demonstracyjna sesji Media3
znajdziesz przykład aplikacji, w której istnieje taki scenariusz.
Klienci zewnętrzni mogą używać interfejsów API, takich jak MediaControllerCompat
starszej biblioteki AndroidX lub android.media.session.MediaController
w ramach Androida. Media3 jest w pełni zgodny wstecznie z poprzednią biblioteką i zapewnia interoperacyjność z interfejsem API Androida.
Użyj kontrolera powiadomień o multimediach
Warto pamiętać, że starsze wersje kontrolerów lub kontrolerów platformy odczytują
tych samych wartości z platformy PlaybackState.getActions()
i
PlaybackState.getCustomActions()
Aby określić działania i działania niestandardowe sesji frameworku, aplikacja może użyć kontrolera powiadomień o mediach i ustawić dostępne polecenia oraz układ niestandardowy. Usługa łączy kontroler powiadomień multimedialnych z Twoją sesją, a sesja używa parametru ConnectionResult
zwracanego przez funkcję onConnect()
, aby skonfigurować działania i działania niestandardowe sesji frameworku.
W przypadku scenariusza tylko na urządzeniach mobilnych aplikacja może udostępnić implementację MediaSession.Callback.onConnect()
, aby ustawić dostępne polecenia i schemat dostosowania do sesji frameworku w ten sposób:
Kotlin
override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { if (session.isMediaNotificationController(controller)) { val sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS.buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build() val playerCommands = ConnectionResult.DEFAULT_PLAYER_COMMANDS.buildUpon() .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .build() // Custom layout and available commands to configure the legacy/framework session. return AcceptedResultBuilder(session) .setCustomLayout( ImmutableList.of( createSeekBackwardButton(customCommandSeekBackward), createSeekForwardButton(customCommandSeekForward)) ) .setAvailablePlayerCommands(playerCommands) .setAvailableSessionCommands(sessionCommands) .build() } // Default commands with default custom layout for all other controllers. return AcceptedResultBuilder(session).build() }
Java
@Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { if (session.isMediaNotificationController(controller)) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS .buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build(); Player.Commands playerCommands = ConnectionResult.DEFAULT_PLAYER_COMMANDS .buildUpon() .remove(COMMAND_SEEK_TO_PREVIOUS) .remove(COMMAND_SEEK_TO_PREVIOUS_MEDIA_ITEM) .remove(COMMAND_SEEK_TO_NEXT) .remove(COMMAND_SEEK_TO_NEXT_MEDIA_ITEM) .build(); // Custom layout and available commands to configure the legacy/framework session. return new AcceptedResultBuilder(session) .setCustomLayout( ImmutableList.of( createSeekBackwardButton(customCommandSeekBackward), createSeekForwardButton(customCommandSeekForward))) .setAvailablePlayerCommands(playerCommands) .setAvailableSessionCommands(sessionCommands) .build(); } // Default commands without default custom layout for all other controllers. return new AcceptedResultBuilder(session).build(); }
Autoryzowanie Androida Auto do wysyłania poleceń niestandardowych
W przypadku korzystania z MediaLibraryService
oraz obsługiwać Androida Auto za pomocą aplikacji mobilnej –
wymaga odpowiednich dostępnych poleceń. W przeciwnym razie obiekt Media3 nie
przychodzące polecenia niestandardowe z tego kontrolera:
Kotlin
override fun onConnect( session: MediaSession, controller: MediaSession.ControllerInfo ): ConnectionResult { val sessionCommands = ConnectionResult.DEFAULT_SESSION_AND_LIBRARY_COMMANDS.buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build() if (session.isMediaNotificationController(controller)) { // [...] See above. } else if (session.isAutoCompanionController(controller)) { // Available session commands to accept incoming custom commands from Auto. return AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build() } // Default commands with default custom layout for all other controllers. return AcceptedResultBuilder(session).build() }
Java
@Override public ConnectionResult onConnect( MediaSession session, MediaSession.ControllerInfo controller) { SessionCommands sessionCommands = ConnectionResult.DEFAULT_SESSION_COMMANDS .buildUpon() .add(customCommandSeekBackward) .add(customCommandSeekForward) .build(); if (session.isMediaNotificationController(controller)) { // [...] See above. } else if (session.isAutoCompanionController(controller)) { // Available commands to accept incoming custom commands from Auto. return new AcceptedResultBuilder(session) .setAvailableSessionCommands(sessionCommands) .build(); } // Default commands without default custom layout for all other controllers. return new AcceptedResultBuilder(session).build(); }
Aplikacja demonstracyjna sesji ma moduł motoryzacyjny, które potwierdza obsługę systemu operacyjnego Automotive, który wymaga osobnego pliku APK.