Aplikacje, które obecnie korzystają z samodzielnej biblioteki com.google.android.exoplayer2
i biblioteki androidx.media
, powinny zostać przeniesione do androidx.media3
. Użyj skryptu migracji, aby przenieść pliki kompilacji Gradle, pliki źródłowe Java i Kotlin oraz pliki układu XML z platformy ExoPlayer 2.19.1
do AndroidaX Media3 1.1.1
.
Przegląd
Przed migracją przeczytaj sekcje poniżej, aby dowiedzieć się więcej o korzyściach związanych z nowymi interfejsami API i interfejsach API do migracji oraz o wymaganiach wstępnych, jakie powinien spełniać projekt aplikacji.
Dlaczego warto przejść na Jetpack Media3
- To nowa wersja ExoPlayer, natomiast
com.google.android.exoplayer2
została wycofana. - Uzyskaj dostęp do interfejsu Player API w różnych komponentach/procesach za pomocą
MediaBrowser
/MediaController
. - Korzystaj z rozszerzonych funkcji interfejsów API
MediaSession
iMediaController
. - Reklamuj możliwości odtwarzania przy użyciu szczegółowej kontroli dostępu.
- Uprość aplikację, usuwając
MediaSessionConnector
iPlayerNotificationManager
. - Zgodność wsteczna z interfejsami API klienta Media-compat
(
MediaBrowserCompat
/MediaControllerCompat
/MediaMetadataCompat
)
Interfejsy API multimediów do migracji na AndroidX Media3
- ExoPlayer i jego rozszerzenia
Obejmuje to wszystkie moduły starszej wersji projektu ExoPlayer z wyjątkiem wycofanego modułu mediasession. Aplikacje lub moduły, w zależności od pakietów wcom.google.android.exoplayer2
, można przenieść za pomocą skryptu migracji. - MediaSessionConnector (w zależności od
androidx.media.*
pakietówandroidx.media:media:1.4.3+
)
UsuńMediaSessionConnector
i użyj zamiast niegoandroidx.media3.session.MediaSession
. - MediaBrowserServiceCompat (w zależności od
androidx.media.*
pakietówandroidx.media:media:1.4.3+
)
Przenieś podklasyandroidx.media.MediaBrowserServiceCompat
do wersjiandroidx.media3.session.MediaLibraryService
i kod zMediaBrowserCompat.MediaItem
doandroidx.media3.common.MediaItem
. - MediaBrowserCompat (w zależności od
android.support.v4.media.*
pakietówandroidx.media:media:1.4.3+
)
Przeprowadź migrację kodu klienta za pomocąMediaBrowserCompat
lubMediaControllerCompat
, aby użyćandroidx.media3.session.MediaBrowser
zandroidx.media3.common.MediaItem
.
Wymagania wstępne
Sprawdzanie, czy projekt jest pod kontrolą źródła
Upewnij się, że zmiany zastosowane przez narzędzia do migracji oparte na skryptach można łatwo cofnąć. Jeśli nie masz jeszcze kontroli nad źródłem nad swoim projektem, to dobry moment, by zacząć od niego. Jeśli z jakiegoś powodu nie chcesz tego zrobić, przed rozpoczęciem migracji utwórz kopię zapasową projektu.
Aktualizowanie aplikacji
Zalecamy zaktualizowanie projektu do 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 przeprowadzasz aktualizację, do wersji obsługiwaną przez skrypt.
Zwiększ wartość ComputeSdkVersion aplikacji do co najmniej 32.
Uaktualnij Gradle i wtyczkę Android Studio do obsługi Gradle do najnowszej wersji, która obsługuje zaktualizowane zależności wymienione powyżej. Na przykład:
- Wersja wtyczki Androida do obsługi Gradle: 7.1.0
- Wersja Gradle: 7.4
Zastąp wszystkie instrukcje importu symbolu wieloznacznego, które używają asterix (*), i używaj w pełni kwalifikowanych instrukcji importu: usuń instrukcje importu z symbolem wieloznacznym i użyj Android Studio, aby zaimportować pełne instrukcje (F2 – Alt/Enter, F2 – Alt/Enter, ...).
Przeprowadź migrację z
com.google.android.exoplayer2.PlayerView
docom.google.android.exoplayer2.StyledPlayerView
. Jest to konieczne, ponieważ w AndroidzieX Media3 nie ma odpowiednikacom.google.android.exoplayer2.PlayerView
.
Migracja odtwarzacza ExoPlayer z obsługą skryptów
Skrypt ułatwia przejście z com.google.android.exoplayer2
do nowego pakietu i struktury modułów w androidx.media3
. Skrypt stosuje w projekcie kilka testów poprawności, a w przypadku niepowodzenia weryfikacji wyświetla ostrzeżenia.
W przeciwnym razie stosuje mapowania klas i pakietów ze zmienioną nazwą w zasobach projektu Gradle Androida napisanego w Javie lub Kotlin.
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
Używanie skryptu migracji
Pobierz skrypt migracji z tagu projektu ExoPlayer na GitHubie odpowiadający wersji, w której została zaktualizowana aplikacja:
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
Uruchom skrypt z funkcją
--help
, aby poznać dostępne opcje.Uruchom skrypt z poleceniem
-l
, aby wyświetlić listę plików wybranych do migracji (użyj polecenia-f
, aby wymusić wyświetlanie bez ostrzeżeń):./media3-migration.sh -l -f /path/to/gradle/project/root
Uruchom skrypt z użyciem funkcji
-m
, aby zmapować pakiety, klasy i moduły na Media3. Uruchomienie skryptu z opcją-m
spowoduje zastosowanie zmian do wybranych plików.- Zatrzymaj przy błędzie weryfikacji bez wprowadzania zmian
./media3-migration.sh -m /path/to/gradle/project/root
- Wymuszone wykonanie
Jeśli skrypt wykryje naruszenie wymagań 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
Wykonaj te czynności ręcznie po uruchomieniu skryptu z opcją -m
:
- Sprawdź, jak skrypt zmienił kod: za pomocą narzędzia do porównywania różnic i rozwiąż potencjalne problemy (możesz zgłosić błąd, jeśli uważasz, że w skrypcie występuje ogólny problem, który został wprowadzony bez zastosowania opcji
-f
). - Utwórz projekt: użyj
./gradlew clean build
lub w Android Studio wybierz Plik > Synchronizuj projekt z Gradle Files, a następnie Utwórz > Oczyść projekt i Utwórz > Odbuduj projekt (monitoruj kompilację na karcie „Kompilacja – Kompilacja” w Android Studio;
Zalecane dalsze kroki:
- Napraw akceptację błędów związanych z korzystaniem z niestabilnych interfejsów API.
- Zastąp wycofane wywołania interfejsu API: użyj sugerowanego zastępczego interfejsu API. Najedź kursorem na ostrzeżenie w Android Studio i zapoznaj się z dokumentem JavaDoc wycofanego symbolu, aby dowiedzieć się, czego należy użyć zamiast danego wywołania.
- Posortować instrukcje importu: otwórz projekt w Android Studio, a następnie kliknij prawym przyciskiem myszy węzeł folderu pakietu w przeglądarce projektu i wybierz Optymalizuj importy przy pakietach zawierających zmienione pliki źródłowe.
Zamień MediaSessionConnector
na androidx.media3.session.MediaSession
W starszej wersji MediaSessionCompat
interfejs MediaSessionConnector
odpowiadał za synchronizację stanu odtwarzacza ze stanem sesji i odbieranie poleceń od kontrolerów, które wymagały przekazania dostępu do odpowiednich metod odtwarzacza. W przypadku AndroidaX Media3 ten proces odbywa się bezpośrednio przez MediaSession
, bez konieczności używania oprogramowania sprzęgającego.
Usuń wszystkie odwołania i wykorzystanie MediaSessionConnector: jeśli do przeniesienia klas i pakietów ExoPlayer użyto automatycznego skryptu, prawdopodobnie Twój kod pozostawał w stanie nieskompilowanym w związku z
MediaSessionConnector
, którego nie można rozwiązać. Android Studio wyświetli uszkodzony kod, gdy spróbujesz skompilować lub uruchomić aplikację.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.3.1"
Zastąp
MediaSessionCompat
wartościąandroidx.media3.session.MediaSession
.W witrynie kodu, w której utworzono starszą wersję
MediaSessionCompat
, użyj poleceniaandroidx.media3.session.MediaSession.Builder
, aby utworzyćMediaSession
. Przekaż odtwarzacz, aby utworzyć konstruktor sesji.val player = ExoPlayer.Builder(context).build() mediaSession = MediaSession.Builder(context, player) .setSessionCallback(MySessionCallback()) .build()
Zaimplementuj funkcję
MySessionCallback
zgodnie z wymaganiami aplikacji. Nie jest to obowiązkowe. Jeśli chcesz zezwolić kontrolerom na dodawanie elementów multimedialnych do odtwarzacza, zaimplementujMediaSession.Callback.onAddMediaItems()
. Obsługuje różne obecne i starsze metody interfejsu API, które dodają elementy multimedialne do odtwarzacza w celu ich odtwarzania. Obejmuje to metodyMediaController.set/addMediaItems()
kontrolera Media3 oraz metodyTransportControls.prepareFrom*/playFrom*
starszego interfejsu API. Przykładową implementację funkcjionAddMediaItems
znajdziesz wPlaybackService
aplikacji demonstracyjnej sesji.Zwolnij sesję multimediów w witrynie kodu, w której została zniszczona sesję przed migracją:
mediaSession?.run { player.release() release() mediaSession = null }
Funkcja MediaSessionConnector
w Media3
W tabeli poniżej znajdziesz interfejsy Media3 API, które obsługują funkcje wcześniej wdrożone w MediaSessionConnector
.
Oprogramowanie sprzęgające sesji MediaSession | AndroidX Media3 |
---|---|
CustomActionProvider |
MediaSession.Callback.onCustomCommand()/
MediaSession.setCustomLayout() |
PlaybackPreparer |
MediaSession.Callback.onAddMediaItems()
(prepare() jest wywoływane wewnętrznie)
|
QueueNavigator |
ForwardingPlayer |
QueueEditor |
MediaSession.Callback.onAddMediaItems() |
RatingCallback |
MediaSession.Callback.onSetRating() |
PlayerNotificationManager |
DefaultMediaNotificationProvider/
MediaNotification.Provider |
Przenieś MediaBrowserService
do MediaLibraryService
AndroidX Media3 wprowadza MediaLibraryService
, który zastępuje MediaBrowserServiceCompat
. Dokument JavaDoc obiektu MediaLibraryService
i jego klasa nadrzędna MediaSessionService
stanowią dobre wprowadzenie do interfejsu API i asynchronicznego modelu programowania usługi.
MediaLibraryService
jest zgodny wstecznie z MediaBrowserService
. Aplikacja kliencka, która używa MediaBrowserCompat
lub MediaControllerCompat
, nadal działa bez zmian w kodzie po połączeniu z MediaLibraryService
. Dla klienta jasno widać, czy aplikacja używa interfejsu MediaLibraryService
czy starszej wersji MediaBrowserServiceCompat
.
Aby zgodność wsteczna działała, musisz zarejestrować oba interfejsy usługi z usługą w
AndroidManifest.xml
. W ten sposób klient znajdzie Twoją usługę według jej wymaganego interfejsu:<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ń tę zależność:implementation "androidx.media3:media3-session:1.3.1"
Zmień usługę tak, aby dziedziczyła ją z
MediaLibraryService
zamiast zMediaBrowserService
. Jak już wspomnieliśmy,MediaLibraryService
jest zgodny ze starszą wersjąMediaBrowserService
. W związku z tym ogólny interfejs API, który ta usługa oferuje klientom, pozostaje bez zmian. Możliwe więc, że aplikacja utrzyma większość logiki wymaganej do wdrożeniaMediaBrowserService
i dostosowania jej do nowej wersjiMediaLibraryService
.Główne różnice w porównaniu ze starszą wersją funkcji
MediaBrowserServiceCompat
:Zaimplementuj metody cyklu życia usługi: metody, które należy zastąpić w samej usłudze, to
onCreate/onDestroy
, gdzie aplikacja przydziela/zwalnia sesję biblioteki, odtwarzacz i inne zasoby. Oprócz standardowych metod cyklu życia usługi aplikacja musi zastąpić właściwośćonGetSession(MediaSession.ControllerInfo)
, aby zwrócićMediaLibrarySession
, która została skompilowana wonCreate
.Implementacja MediaLibraryService.MediaLibrarySessionCallback: utworzenie sesji wymaga modułu
MediaLibraryService.MediaLibrarySessionCallback
, który implementuje metody interfejsu API domeny. Dlatego zamiast zastępować metody interfejsu API starszej usługi, zastąpisz metody dostępne w metodzieMediaLibrarySession.Callback
.Wywołanie zwrotne jest następnie używane do utworzenia
MediaLibrarySession
:mediaLibrarySession = MediaLibrarySession.Builder(this, player, MySessionCallback()) .build()
Pełny interfejs API MediaLibrarySessionCallback znajdziesz w dokumentacji interfejsu API.
Implementacja
MediaSession.Callback.onAddMediaItems()
: wywołanie zwrotneonAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>)
obsługuje różne bieżące i starsze metody interfejsu API, które dodają elementy multimedialne do odtwarzacza na potrzeby ich odtwarzania w sposób zgodny wstecznie. Obejmuje to metodyMediaController.set/addMediaItems()
kontrolera Media3 i metodyTransportControls.prepareFrom*/playFrom*
starszego interfejsu API. Przykładową implementację wywołania zwrotnego znajdziesz wPlaybackService
aplikacji demonstracyjnej sesji.AndroidX Media3 używa
androidx.media3.common.MediaItem
zamiast MediaBrowserCompat.MediaItem i MediaMetadataCompat. Musisz odpowiednio zmienić części kodu powiązane ze starszymi klasami lub zmapować je na elementMediaItem
Media3.Ogólny model programowania asynchronicznego został zmieniony na
Futures
w przeciwieństwie do metodyResult
z odłączanym elementemMediaBrowserServiceCompat
. Implementacja Twojej usługi może zwracać asynchroniczną wartośćListenableFuture
, zamiast odłączać wynik lub zwracać natychmiastową przyszłość, aby bezpośrednio zwrócić wartość.
Usuń PlayerPowiadomienie Manager
Urządzenie MediaLibraryService
automatycznie obsługuje powiadomienia o multimediach, a urządzenie PlayerNotificationManager
można usunąć, jeśli używasz MediaLibraryService
lub MediaSessionService
.
Aplikacja może dostosować powiadomienie, ustawiając w onCreate()
niestandardowy parametr MediaNotification.Provider
, który zastąpi DefaultMediaNotificationProvider
. W razie potrzeby MediaLibraryService
uruchomi usługę na pierwszym planie.
Zastąpienie MediaLibraryService.updateNotification()
może w ten sposób przejąć pełną własność publikowania powiadomienia oraz, w razie potrzeby, uruchamiać i zatrzymywać usługę na pierwszym planie.
Migracja kodu klienta przy użyciu MediaBrowser
W AndroidzieX Media3 MediaBrowser
implementuje interfejsy MediaController/Player
i może służyć do sterowania odtwarzaniem multimediów poza przeglądaniem biblioteki multimediów. Jeśli musisz utworzyć elementy MediaBrowserCompat
i MediaControllerCompat
w starszej wersji, możesz zrobić to samo, używając tylko MediaBrowser
w Media3.
Możesz utworzyć MediaBrowser
i poczekać na połączenie 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)
}
Zapoznaj się z sekcją Sterowanie odtwarzaniem w sesji multimediów, aby dowiedzieć się, jak utworzyć komponent MediaController
służący do sterowania odtwarzaniem w tle.
Dalsze czynności i czyszczenie
Niestabilne błędy interfejsu API
Po migracji do Media3 mogą pojawić się błędy linta dotyczące niestabilnego użycia interfejsu API.
Te interfejsy API są bezpieczne w użyciu, a błędy lintowania to efekt uboczny naszych nowych gwarancji zgodności plików binarnych. Jeśli nie wymagasz ścisłej zgodności plików binarnych, możesz bezpiecznie pominąć te błędy za pomocą adnotacji @OptIn
.
Tło
Ani ExoPlayer w wersji 1, ani 2 nie daje ścisłych gwarancji zgodności plików binarnych z kolejnymi wersjami. Interfejs ExoPlayer API jest z założenia bardzo duży, aby umożliwiać aplikacjom dostosowywanie niemal każdego aspektu odtwarzania. W kolejnych wersjach ExoPlayera od czasu do czasu wprowadzane były zmiany nazw symboli lub inne zmiany powodujące niezgodność (np. nowe wymagane metody interfejsów). W większości przypadków awarie zostały złagodzone przez wprowadzenie nowego symbolu i wycofanie starego symbolu w kilku wersjach, aby dać programistom czas na migrację zastosowań, ale nie zawsze było to możliwe.
Te zmiany powodujące niezgodność spowodowały, że użytkownicy bibliotek ExoPlayer w wersjach 1 i 2 napotkali 2 problemy:
- Uaktualnienie do wersji ExoPlayer może spowodować przerwanie kompilowania kodu.
- Aplikacja, która korzystała z platformy ExoPlayer zarówno bezpośrednio, jak i za pomocą biblioteki pośredniej, musiała sprawdzić, czy obie zależności są tej samej wersji. W przeciwnym razie niezgodności plików binarnych mogą doprowadzić do awarii środowiska wykonawczego.
Ulepszenia w Media3
Media3 gwarantuje zgodność plików binarnych z podzbiorem platformy API. Elementy, które nie gwarantują zgodności z plikami binarnymi, są oznaczone symbolem @UnstableApi
. Aby to rozróżnić, użycie niestabilnych symboli interfejsu API generuje błąd lintowania, chyba że jest opatrzony adnotacją @OptIn
.
Po migracji z ExoPlayer 2 do Media3 możesz napotkać wiele niestabilnych błędów lintowania interfejsu API. Może się wydawać, że Media3 jest mniej stabilna niż ExoPlayer v2. To nieprawda. „Niestabilne” części interfejsu Media3 API mają taki sam poziom stabilności jak cała powierzchnia interfejsu ExoPlayer v2, a gwarancje stabilnej powierzchni interfejsu Media3 API nie są w ogóle dostępne w ExoPlayer v2. Różni się tylko tym, że błąd lintowania ostrzega teraz o różnych poziomach stabilności.
Obsługa niestabilnych błędów lintowych interfejsu API
Szczegółowe informacje o tym, jak za pomocą @OptIn
dodawać adnotacje o zastosowaniach niestabilnych interfejsów API w językach Java i Kotlin, znajdziesz w sekcji dotyczącej rozwiązywania problemów z tymi błędami lint.
Wycofane interfejsy API
Możesz zauważyć, że wywołania wycofanych interfejsów API są przekreślone w Android Studio. Zalecamy zastąpienie takich wywołań odpowiednią alternatywą. Najedź na ten symbol, aby zobaczyć dokument JavaDoc informujący, którego interfejsu API należy użyć.
Przykłady kodu i aplikacje demonstracyjne
- Aplikacja demonstracyjna sesji na AndroidzieX Media3 (urządzenia mobilne i Wear OS)
- Działania niestandardowe
- Powiadomienie w interfejsie systemu, MediaButton/BT
- Sterowanie odtwarzaniem w Asystencie Google
- UAMP: Android Media Player (branch media3) (urządzenia mobilne, AutomotiveOS)
- Powiadomienie w interfejsie systemu, MediaButton/BT, wznawianie odtwarzania
- Sterowanie odtwarzaniem w Asystencie Google/na Wear OS
- AutomotiveOS: niestandardowe polecenie i logowanie