Aplikacje, które obecnie używają samodzielnej biblioteki com.google.android.exoplayer2
i biblioteki androidx.media
, należy przenieść do androidx.media3
. Użyj skryptu migracji, aby przenieść pliki kompilacji Gradle, pliki źródłowe Javy i Kotlin oraz pliki układu XML z ExoPlayera2.19.1
do AndroidX Media31.1.1
.
Omówienie
Zanim przeprowadzisz migrację, zapoznaj się z następującymi sekcjami, aby dowiedzieć się więcej o korzyściach płynących z nowych interfejsów API, interfejsach API, które należy przenieść, oraz wymaganiach wstępnych, które musi spełniać projekt aplikacji.
Dlaczego warto przejść na Jetpack Media3
- Jest to nowa wersja ExoPlayera, a
com.google.android.exoplayer2
został wycofany. - Uzyskaj dostęp do interfejsu Player API w różnych komponentach i procesach za pomocą interfejsów
MediaBrowser
iMediaController
. - Korzystanie z rozszerzonych możliwości interfejsów API
MediaSession
iMediaController
. - Reklamowanie możliwości odtwarzania dzięki szczegółowej kontroli dostępu.
- Uprość aplikację, usuwając
MediaSessionConnector
iPlayerNotificationManager
. - Kompatybilny wstecz z interfejsami API klienta zgodnymi z mediami (
MediaBrowserCompat
/MediaControllerCompat
/MediaMetadataCompat
).
Interfejsy Media API do migracji do Media3 w AndroidX
- ExoPlayer i jego rozszerzenia
Obejmuje to wszystkie moduły starszego projektu ExoPlayer z wyjątkiem modułu mediasession, który został wycofany. Aplikacje lub moduły (w zależności od pakietów wcom.google.android.exoplayer2
) można przenieść za pomocą skryptu migracyjnego. - MediaSessionConnector (w zależności od pakietów
androidx.media.*
androidx.media:media:1.4.3+
)
UsuńMediaSessionConnector
i zamiast tego użyjandroidx.media3.session.MediaSession
. - MediaBrowserServiceCompat (w zależności od pakietów
androidx.media.*
wandroidx.media:media:1.4.3+
)
Przenieś podklasyandroidx.media.MediaBrowserServiceCompat
doandroidx.media3.session.MediaLibraryService
i kod korzystający zMediaBrowserCompat.MediaItem
doandroidx.media3.common.MediaItem
. - MediaBrowserCompat (w zależności od pakietów
android.support.v4.media.*
wandroidx.media:media:1.4.3+
)
Przenieś kod klienta za pomocą pakietuMediaBrowserCompat
lub pakietuMediaControllerCompat
, aby używać pakietuandroidx.media3.session.MediaBrowser
z poziomuandroidx.media3.common.MediaItem
.
Wymagania wstępne
Sprawdzanie, czy projekt jest objęty kontrolą wersji
Zadbaj o to, aby zmiany wprowadzone przez narzędzia do migracji oparte na skryptach można było łatwo cofnąć. Jeśli nie masz jeszcze projektu objętego kontrolą wersji, teraz jest dobry moment, aby zacząć. Jeśli z jakiegoś powodu nie chcesz tego zrobić, przed rozpoczęciem migracji utwórz kopię zapasową projektu.
Aktualizowanie aplikacji
Zalecamy zaktualizowanie projektu, aby używać najnowszej wersji biblioteki ExoPlayer, i usunięcie wszystkich wywołań wycofanych metod. Jeśli zamierzasz użyć skryptu podczas migracji, musisz dopasować wersję, do której aktualizujesz usługę, do wersji obsługiwanej przez skrypt.
Zwiększ wartość parametru compileSdkVersion aplikacji do co najmniej 32.
Zaktualizuj Gradle i wtyczkę Gradle do Androida Studio do najnowszej wersji, która współpracuje z powyżej wymienionymi zaktualizowanymi zależnościami. Na przykład:
- Wersja wtyczki Androida do obsługi Gradle: 7.1.0
- Wersja Gradle: 7.4
Zastąp wszystkie instrukcje importu z użyciem gwiazdki, które używają gwiazdki (*), i użyj w pełni kwalifikowanych instrukcji importu: usuń instrukcje importu z użyciem gwiazdki i użyj Android Studio do zaimportowania w pełni kwalifikowanych instrukcji (F2 – Alt/Enter, F2 – Alt/Enter, …).
Przenieś z
com.google.android.exoplayer2.PlayerView
docom.google.android.exoplayer2.StyledPlayerView
. Jest to konieczne, ponieważ w AndroidX Media3 nie ma odpowiednika funkcjicom.google.android.exoplayer2.PlayerView
.
Migracja ExoPlayer z obsługą skryptów
Skrypt ułatwia przejście z wersji com.google.android.exoplayer2
na nową strukturę pakietu i modułów w ramach androidx.media3
. Skrypt stosuje w projekcie niektóre weryfikacje i wypisuje ostrzeżenia, jeśli weryfikacja się nie powiedzie.
W przeciwnym razie zastosuje mapowania przemianowanych klas i pakietów w zasobach projektu Androida w Gradle napisanego w Javie lub Kotlinie.
usage: ./media3-migration.sh [-p|-c|-d|-v]|[-m|-l [-x <path>] [-f] PROJECT_ROOT]
PROJECT_ROOT: path to your project root (location of 'gradlew')
-p: list package mappings and then exit
-c: list class mappings (precedence over package mappings) and then exit
-d: list dependency mappings and then exit
-l: list files that will be considered for rewrite and then exit
-x: exclude the path from the list of file to be changed: 'app/src/test'
-m: migrate packages, classes and dependencies to AndroidX Media3
-f: force the action even when validation fails
-v: print the exoplayer2/media3 version strings of this script
-h, --help: show this help text
Korzystanie ze skryptu migracji
Pobierz skrypt migracji z tagu projektu ExoPlayer na GitHubie odpowiadającego wersji, do której zaktualizowano Twoją aplikację:
curl -o media3-migration.sh \ "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
Ustaw skrypt jako wykonywalny:
chmod 744 media3-migration.sh
Aby poznać opcje, uruchom skrypt z użyciem parametru
--help
.Uruchom skrypt z użyciem parametru
-l
, aby wyświetlić listę plików wybranych do migracji (użyj polecenia-f
, aby wymusić wyświetlanie strony bez ostrzeżeń):./media3-migration.sh -l -f /path/to/gradle/project/root
Uruchom skrypt z opcją
-m
, aby zmapować pakiety, klasy i moduły do Media3. Uruchomienie skryptu z opcją-m
spowoduje zastosowanie zmian do wybranych plików.- Zatrzymaj po wystąpieniu błędu weryfikacji bez wprowadzania zmian
./media3-migration.sh -m /path/to/gradle/project/root
- Wymuszone wykonanie
Jeśli skrypt wykryje naruszenie warunków wstępnych, migrację można wymusić za pomocą flagi
-f
:./media3-migration.sh -m -f /path/to/gradle/project/root
# list files selected for migration when excluding paths
./media3-migration.sh -l -x "app/src/test/" -x "service/" /path/to/project/root
# migrate the selected files
./media3-migration.sh -m -x "app/src/test/" -x "service/" /path/to/project/root
Po uruchomieniu skryptu za pomocą opcji -m
wykonaj te czynności ręcznie:
- Sprawdź, jak skrypt zmienił Twój kod: użyj narzędzia do porównywania i rozwiąż potencjalne problemy (rozważ zgłoszenie błędu, jeśli uważasz, że skrypt ma ogólny problem, który został wprowadzony bez opcji
-f
). - Kompilacja projektu: użyj
./gradlew clean build
lub w Android Studio wybierz Plik > Synchronizuj projekt z plikami Gradle, a następnie Kompiluj > Wyczyść projekt, a potem Kompiluj > Odbuduj projekt ponownie (monitoruj kompilację na karcie Kompilacja – Dane wyjściowe kompilacji w Android Studio).
Zalecane dalsze kroki:
- Rozwiąż problemy z błędami dotyczącymi używania niestabilnych interfejsów API.
- Zastąp wycofane wywołania interfejsu API: użyj sugerowanego interfejsu API. W Android Studio najedź kursorem na ostrzeżenie i otwórz JavaDoc wycofanego symbolu, aby dowiedzieć się, czego użyć zamiast danego wywołania.
- Porządkuj instrukcje importu: otwórz projekt w Android Studio, a potem w przeglądarce projektu kliknij prawym przyciskiem myszy węzeł folderu pakietu i w przypadku pakietów zawierających zmienione pliki źródłowe kliknij Optymalizuj importy.
Zastąp MediaSessionConnector
tekstem androidx.media3.session.MediaSession
W starszym świecie MediaSessionCompat
obiekt MediaSessionConnector
odpowiadał za synchronizowanie stanu odtwarzacza ze stanem sesji oraz za odbieranie poleceń od kontrolerów, które wymagały delegowania do odpowiednich metod odtwarzacza. W AndroidX Media3 MediaSession
robi to bezpośrednio bez konieczności stosowania oprogramowania sprzęgającego.
Usuń wszystkie odwołania i użycia MediaSessionConnector: jeśli do migracji klas i pakietów ExoPlayera został użyty skrypt automatyczny, prawdopodobnie skrypt pozostawił kod w stanie, w którym nie można go skompilować, w odniesieniu do
MediaSessionConnector
, którego nie można rozwiązać. Android Studio wyświetli uszkodzony kod przy próbie skompilowania lub uruchomienia aplikacji.W pliku
build.gradle
, w którym utrzymujesz zależności, dodaj zależność implementacji do modułu sesji Media3 w AndroidX i usuń starszą zależność:implementation "androidx.media3:media3-session:1.4.1"
Zastąp
MediaSessionCompat
elementemandroidx.media3.session.MediaSession
.W witrynie kodu, w której została utworzona starsza wersja
MediaSessionCompat
, użyjandroidx.media3.session.MediaSession.Builder
, aby utworzyćMediaSession
. Prześlij odtwarzacz, aby utworzyć kreator sesji.val player = ExoPlayer.Builder(context).build() mediaSession = MediaSession.Builder(context, player) .setSessionCallback(MySessionCallback()) .build()
Wdrożyć
MySessionCallback
zgodnie z wymaganiami aplikacji. To pole jest opcjonalne. Jeśli chcesz zezwolić kontrolerom na dodawanie elementów multimedialnych do odtwarzacza, zaimplementuj elementMediaSession.Callback.onAddMediaItems()
. Obsługuje on różne bieżące i stare metody interfejsu API, które dodają do odtwarzacza elementy multimediów w sposób zgodny wstecznie. Obejmuje to metodyMediaController.set/addMediaItems()
kontrolera Media3, a także metodyTransportControls.prepareFrom*/playFrom*
starszego interfejsu API. Przykładową implementacjęonAddMediaItems
znajdziesz wPlaybackService
aplikacji demonstracyjnej sesji.Zwolnij sesję multimediów w witrynie kodu, w której sesja została zniszczona przed migracją:
mediaSession?.run { player.release() release() mediaSession = null }
Funkcje MediaSessionConnector
w Media3
W tabeli poniżej znajdziesz interfejsy API Media3, które obsługują funkcje wcześniej zaimplementowane w MediaSessionConnector
.
MediaSessionConnector | AndroidX Media3 |
---|---|
CustomActionProvider |
MediaSession.Callback.onCustomCommand()/
MediaSession.setCustomLayout() |
PlaybackPreparer |
MediaSession.Callback.onAddMediaItems()
(prepare() jest wywoływany wewnętrznie)
|
QueueNavigator |
ForwardingPlayer |
QueueEditor |
MediaSession.Callback.onAddMediaItems() |
RatingCallback |
MediaSession.Callback.onSetRating() |
PlayerNotificationManager |
DefaultMediaNotificationProvider/
MediaNotification.Provider |
Przenoszenie danych z MediaBrowserService
do MediaLibraryService
AndroidX Media3 wprowadza MediaLibraryService
, który zastępuje MediaBrowserServiceCompat
. JavaDoc usługi MediaLibraryService
i jej superklasy MediaSessionService
stanowią dobre wprowadzenie do interfejsu API i asymetrycznego modelu programowania tej usługi.
Element MediaLibraryService
jest zgodny wstecz z MediaBrowserService
. Aplikacja kliencka, która używa MediaBrowserCompat
lub MediaControllerCompat
, może w dalszym ciągu działać bez zmian w kodzie po połączeniu się z MediaLibraryService
. Klient widzi, czy Twoja aplikacja używa interfejsu MediaLibraryService
czy starszego MediaBrowserServiceCompat
.
Aby zgodność wsteczna działała, musisz zarejestrować oba interfejsy usług w usłudze w
AndroidManifest.xml
. W ten sposób klient znajdzie Twoją usługę przez wymagany interfejs usługi:<service android:name=".MusicService" android:exported="true"> <intent-filter> <action android:name="androidx.media3.session.MediaLibraryService"/> <action android:name="android.media.browse.MediaBrowserService" /> </intent-filter> </service>
W pliku
build.gradle
, w którym przechowujesz zależności, dodaj zależność implementacji do modułu sesji AndroidX Media3 i usuń starszą zależność:implementation "androidx.media3:media3-session:1.4.1"
Zmień usługę tak, aby dziedziczyła z poziomu usługi
MediaLibraryService
, a nie z poziomu usługiMediaBrowserService
. Jak już wspomnieliśmy, usługaMediaLibraryService
jest zgodna ze starszą wersją usługiMediaBrowserService
. W związku z tym interfejs API, który usługa oferuje klientom, pozostaje taki sam. Możliwe więc, że aplikacja zachowa większość logiki niezbędną do zaimplementowania elementuMediaBrowserService
i dostosowania go do nowej wersjiMediaLibraryService
.Najważniejsze różnice w porównaniu z wersją klasyczną
MediaBrowserServiceCompat
:Zaimplementuj metody cyklu życia usługi: metody, które trzeba zastąpić w samej usłudze, to
onCreate/onDestroy
, gdzie aplikacja alokuje lub zwalnia sesję biblioteki, odtwarzacz i inne zasoby. Oprócz standardowych metod cyklu życia usługi aplikacja musi zastąpić metodęonGetSession(MediaSession.ControllerInfo)
, aby zwrócić metodęMediaLibrarySession
utworzoną wonCreate
.Zaimplementuj MediaLibraryService.MediaLibrarySessionCallback: tworzenie sesji wymaga
MediaLibraryService.MediaLibrarySessionCallback
, który implementuje metody interfejsu API domeny. Zamiast zastąpić metody interfejsu API starszej usługi, zastąpisz metody usługiMediaLibrarySession.Callback
.Wywołanie zwrotne jest następnie używane do utworzenia
MediaLibrarySession
:mediaLibrarySession = MediaLibrarySession.Builder(this, player, MySessionCallback()) .build()
W dokumentacji interfejsu API odszukaj pełny interfejs API MediaLibrarySessionCallback.
Wdróż
MediaSession.Callback.onAddMediaItems()
: wywołanie zwrotneonAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>)
obsługuje różne obecne i starsze metody interfejsu API, które dodają elementy multimedialne do odtwarzacza, aby umożliwić odtwarzanie w sposób zgodny wstecznie. Dotyczy to metodMediaController.set/addMediaItems()
kontrolera Media3 oraz metodTransportControls.prepareFrom*/playFrom*
starszego interfejsu API. Przykładową implementację wywołania zwrotnego znajdziesz wPlaybackService
aplikacji demonstracyjnej sesji.AndroidX Media3 używa interfejsu
androidx.media3.common.MediaItem
zamiast interfejsów MediaBrowserCompat.MediaItem i MediaMetadataCompat. Odpowiednio trzeba zmienić te części kodu, które są powiązane ze starszymi klasami, lub zmapować je na Media3MediaItem
.Ogólny model programowania asynchronicznego został zmieniony na
Futures
, co odróżnia go od podejściaResult
wMediaBrowserServiceCompat
, w którym można odłączać komponenty. Implementacja usługi może zwrócić asynchronicznąListenableFuture
zamiast odłączać wynik lub zwrócić natychmiastową wartość Future.
Usuń PlayerNotificationManager
MediaLibraryService
automatycznie obsługuje powiadomienia o multimediach, a element PlayerNotificationManager
można usunąć, gdy używasz elementu MediaLibraryService
lub MediaSessionService
.
Aplikacja może spersonalizować powiadomienie, ustawiając niestandardowe MediaNotification.Provider
w onCreate()
, które zastępuje DefaultMediaNotificationProvider
. Następnie MediaLibraryService
uruchamia usługę na pierwszym planie zgodnie z potrzebami.
Zastępując MediaLibraryService.updateNotification()
, aplikacja może przejąć pełną kontrolę nad publikowaniem powiadomień i uruchamianiem/zatrzymywaniem usługi na pierwszym planie w razie potrzeby.
Migracja kodu klienta za pomocą MediaBrowser
W AndroidX Media3 MediaBrowser
implementuje interfejsy MediaController/Player
i może służyć do sterowania odtwarzaniem multimediów oprócz przeglądania multimediów w bibliotece. Jeśli w starszej wersji musiałeś utworzyć MediaBrowserCompat
i MediaControllerCompat
, możesz to zrobić w Media3, używając tylko MediaBrowser
.
Można utworzyć MediaBrowser
i zaczekać na nawiązanie połączenia z usługą:
scope.launch {
val sessionToken =
SessionToken(context, ComponentName(context, MusicService::class.java)
browser =
MediaBrowser.Builder(context, sessionToken))
.setListener(BrowserListener())
.buildAsync()
.await()
// Get the library root to start browsing the library.
root = browser.getLibraryRoot(/* params= */ null).await();
// Add a MediaController.Listener to listen to player state events.
browser.addListener(playerListener)
playerView.setPlayer(browser)
}
Przeczytaj artykuł o sterowaniu odtwarzaniem w trakcie sesji multimediów, aby dowiedzieć się, jak utworzyć element MediaController
do sterowania odtwarzaniem w tle.
Dalsze kroki i czyszczenie
Błędy niestabilnego interfejsu API
Po migracji na Media3 mogą pojawić się błędy lint dotyczące niestabilnego użycia interfejsu API.
Te interfejsy API są bezpieczne w użyciu, a błędy lint są wynikiem naszych nowych gwarancji zgodności binarnej. Jeśli nie wymagasz ścisłej zgodności plików binarnych, te błędy można bezpiecznie powstrzymać za pomocą adnotacji @OptIn
.
Tło
Ani ExoPlayer w wersji 1, ani w wersji 2 nie zapewniały ścisłej gwarancji zgodności binarnej biblioteki w kolejnych wersjach. Interfejs ExoPlayer API jest bardzo rozbudowany, aby umożliwić aplikacjom dostosowywanie niemal wszystkich aspektów odtwarzania. Kolejne wersje ExoPlayera mogą wprowadzać zmiany nazw symboli lub inne zmiany wymagające aktualizacji (np. nowe wymagane metody w interfejsach). W większości przypadków udało się ograniczyć te problemy przez wprowadzenie nowego symbolu i wycofanie starego w kilku wersjach, aby dać deweloperom czas na przeniesienie zastosowań. Nie zawsze było to jednak możliwe.
Te zmiany spowodowały 2 problemy dla użytkowników bibliotek ExoPlayer w wersji 1 i 2:
- Przejście na nowszą wersję ExoPlayera może spowodować, że kod przestanie się kompilować.
- Aplikacja, która korzystała z ExoPlayera bezpośrednio i za pomocą pośredniej biblioteki, musiała mieć te zależności w tej samej wersji. W przeciwnym razie niezgodności binarne mogłyby spowodować awarie w czasie działania.
Ulepszenia w Media3
Media3 gwarantuje zgodność binarną w przypadku podzbioru interfejsu API. Elementy, które nie gwarantują zgodności binarnej, są oznaczone jako @UnstableApi
. Aby wyraźnie zaznaczyć to rozróżnienie, użycie niestabilnych symboli interfejsu API powoduje błąd lint, chyba że zostaną one opatrzone adnotacją @OptIn
.
Po migracji z ExoPlayer v2 do Media3 możesz napotkać wiele niestabilnych błędów interfejsu API. Może to sprawiać wrażenie, że Media3 jest „mniej stabilna” niż ExoPlayer v2. Nie jest to prawda. Części interfejsu Media3 API o charakterze „niestabilnym” mają ten sam poziom stabilności co całość interfejsu API ExoPlayer w wersji 2, a gwarancje stabilności interfejsu Media3 API nie są w ogóle dostępne w ExoPlayerze w wersji 2. Różnica polega na tym, że błąd lint informuje teraz o różnych poziomach stabilności.
Obsługa niestabilnych błędów lint w interfejsie API
Zapoznaj się z sekcją rozwiązywania problemów z tymi błędami lintowania, aby dowiedzieć się, jak w @OptIn
dodawać adnotacje do niestabilnych interfejsów API w Javie i Kotlinie.
Wycofane interfejsy API
W Android Studio możesz zauważyć, że wywołania wycofanych interfejsów API są przekreślone. Zalecamy zastąpienie takich wywołań odpowiednimi alternatywami. Najedź kursorem na symbol, aby wyświetlić informacje w JavaDoc, które podają, którego interfejsu API należy użyć zamiast tego.
Przykłady kodu i aplikacje demonstracyjne
- Aplikacja demonstracyjna sesji Media3 w AndroidX (na urządzenia mobilne i Wear OS)
- Działania niestandardowe
- Powiadomienie w interfejsie użytkownika, przycisk multimedialny/BT
- Sterowanie odtwarzaniem za pomocą Asystenta Google
- UAMP: odtwarzacz multimediów na Androida (gałąź media3) (mobilne, AutomotiveOS)
- Powiadomienie w interfejsie systemu, MediaButton/BT, wznowienie odtwarzania
- Sterowanie odtwarzaniem za pomocą Asystenta Google lub Wear OS
- AutomotiveOS: polecenie i logowanie niestandardowe