Przewodnik po migracji na AndroidaX Media3

Aplikacje, które obecnie używają samodzielnej usługi com.google.android.exoplayer2 , a biblioteka androidx.media powinna zostać przeniesiona do androidx.media3. Używaj skryptu migracji do przenoszenia plików kompilacji Gradle, Javy Pliki źródłowe Kotlin i pliki układu XML z ExoPlayer Z 2.19.1 na AndroidX Media3 1.1.1.

Omówienie

Przed migracją zapoznaj się z sekcjami poniżej, aby dowiedzieć się więcej korzyści płynące z nowych interfejsów API i ich migracji oraz wymagania wstępne jakie powinny spełniać projekt aplikacji.

Dlaczego warto przejść na Jetpack Media3

  • To nowe miejsce na ExoPlayer, natomiast com.google.android.exoplayer2 to wycofane.
  • Dostęp do Player API w różnych komponentach/procesach możesz uzyskać za pomocą MediaBrowser/MediaController.
  • Korzystaj z rozszerzonych możliwości interfejsu MediaSession i interfejsu API MediaController.
  • Reklamuj możliwości odtwarzania za pomocą szczegółowej kontroli dostępu.
  • Uprość swoją aplikację, usuwając funkcje MediaSessionConnector i PlayerNotificationManager
  • Zgodność wsteczna z interfejsami API klienta kompatybilnych z mediami (MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat).

Interfejsy Media API zostaną przeniesione do AndroidX Media3

  • ExoPlayer i jego rozszerzenia
    Obejmuje to wszystkie moduły starszego projektu ExoPlayer z wyjątkiem Moduł mediasession, który został wycofany. Aplikacje lub moduły w zależności od tego, pakiety w com.google.android.exoplayer2 można przenieść za pomocą skrypt migracji.
  • MediaSessionConnector (w zależności od androidx.media.* pakietów po androidx.media:media:1.4.3+)
    Usuń MediaSessionConnector i użyj androidx.media3.session.MediaSession.
  • Media BrowserServiceCompat (w zależności od androidx.media.* pakietów po androidx.media:media:1.4.3+)
    Przenieś podklasy klasy androidx.media.MediaBrowserServiceCompat do androidx.media3.session.MediaLibraryService i kod za pomocą MediaBrowserCompat.MediaItem do androidx.media3.common.MediaItem.
  • Media BrowserCompat (w zależności od android.support.v4.media.* pakietów po androidx.media:media:1.4.3+)
    Przeprowadź migrację kodu klienta za pomocą MediaBrowserCompat lub MediaControllerCompat, aby użyć androidx.media3.session.MediaBrowser dzięki androidx.media3.common.MediaItem.

Wymagania wstępne

  1. Sprawdzanie, czy projekt znajduje się pod kontrolą źródła

    Zadbaj o to, aby zmiany wprowadzone przez narzędzia do migracji oparte na skryptach można było łatwo cofnąć. Jeśli Twój projekt nie jest jeszcze kontrolowany nad źródłem, to jest dobry moment aby zacząć od niego. Jeśli z jakiegoś powodu nie chcesz tego robić, utwórz kopii zapasowej projektu przed rozpoczęciem migracji.

  2. Aktualizowanie aplikacji

    • Zalecamy zaktualizowanie projektu tak, aby używał najnowszą wersję biblioteki ExoPlayer i usuń wszystkie wywołań wycofanych metod. Jeśli chcesz użyj skryptu migracji, musisz dopasować która jest obsługiwana przez skrypt.

    • Zwiększ parametr buildSdkVersion aplikacji do co najmniej 32.

    • Uaktualnij Gradle i wtyczkę Android Studio Gradle do najnowszej wersji która działa ze zaktualizowanymi zależnościami przedstawionymi powyżej. Dla: instancja:

      • Wersja wtyczki Androida do obsługi Gradle: 7.1.0
      • Wersja Gradle: 7.4
    • Zastąp wszystkie instrukcje importu symboli zastępczych, które używają asterksu (*) i użyj pełnych i jednoznacznych instrukcji importu: usuń symbol wieloznaczny importując wyciągi i za pomocą Android Studio zaimportujemy instrukcje (F2 – Alt/Enter, F2 – Alt/Enter itd.).

    • Migracja z usługi com.google.android.exoplayer2.PlayerView do com.google.android.exoplayer2.StyledPlayerView. Jest to konieczne bo nie ma odpowiednika com.google.android.exoplayer2.PlayerView w AndroidX Media3.

Migracja ExoPlayer z obsługą skryptów

Skrypt ułatwia przejście z com.google.android.exoplayer2 do nowej pakietu i modułów w sekcji androidx.media3. Skrypt zostanie zastosowany testy weryfikacji projektu, a w przypadku niepowodzenia – wyświetlane są ostrzeżenia. W przeciwnym razie stosowane są mapowania zmienionych klas i pakietów w sekcji zasobów projektu Gradle na Androida napisanego w języku Java 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

Korzystanie ze skryptu migracji

  1. Pobierz skrypt migracji z tagu projektu ExoPlayer w witrynie GitHub odpowiadający wersji, do której aplikacja została zaktualizowana:

    curl -o media3-migration.sh \
      "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
    
  2. Ustaw skrypt jako wykonywalny:

    chmod 744 media3-migration.sh
    
  3. Aby poznać opcje, uruchom skrypt z użyciem parametru --help.

  4. Uruchom skrypt z użyciem parametru -l, aby wyświetlić listę plików wybranych dla migracja (aby wymusić wyświetlanie strony bez ostrzeżeń, użyj polecenia -f):

    ./media3-migration.sh -l -f /path/to/gradle/project/root
    
  5. Uruchom skrypt z użyciem parametru -m, aby zmapować pakiety, klasy i moduły na Media3. Uruchomienie skryptu z opcją -m spowoduje zastosowanie zmian do wybranych .

    • 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 wymagań wstępnych, można przeprowadzić migrację wymuszone przez flagę -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 z opcją -m wykonaj te ręczne czynności:

  1. Sprawdź, jak skrypt zmienił Twój kod: użyj narzędzia różnic i rozwiąż problem. potencjalnych problemów (rozważ zgłoszenie błędu, jeśli uważasz, że skrypt zawiera ogólny problem, który został wprowadzony bez podania opcji -f).
  2. Utwórz projekt: użyj ./gradlew clean build lub Androida. W Studio kliknij kolejno Plik > Zsynchronizuj projekt z plikami Gradle, a następnie Kompilacja > Wyczyść projekt, a następnie Build > (Kompilacja) Przebuduj projekt (monitoruj kompilację w „Kompilacja – dane wyjściowe kompilacji” w Android Studio.
.

Zalecane dodatkowe czynności:

  1. rozwiązać problem z akceptacją błędów dotyczących używania niestabilnych interfejsów API.
  2. 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, by dowiedzieć się, którego użyć zamiast danego wywołania.
  3. Posortuj 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 Zoptymalizuj importowanie pakietów, które zawierają zmienione pliki źródłowe.

Zamień MediaSessionConnector na androidx.media3.session.MediaSession

W starszym świecie MediaSessionCompat obiekt MediaSessionConnector był odpowiada za synchronizację stanu odtwarzacza ze stanem sesji i otrzymywanie poleceń od kontrolerów, które wymagają przekazania dostępu do odpowiednich metod grania. W AndroidX Media3 MediaSession robi to bezpośrednio bez konieczności stosowania oprogramowania sprzęgającego.

  1. Usuń wszystkie odniesienia i wykorzystanie interfejsu MediaSessionConnector: jeśli automatycznego skryptu do migracji klas i pakietów ExoPlayer, skrypt prawdopodobnie pozostawił Twój kod w stanie niemożliwym do skompilowania w odniesieniu do MediaSessionConnector, których nie można rozwiązać. Android Studio podczas próby skompilowania lub uruchomienia aplikacji pojawi się uszkodzony kod.

  2. W pliku build.gradle, w którym przechowujesz zależności, dodaj parametr zależność wdrożenia do modułu sesji AndroidX Media3 i usuń starszą zależność:

    implementation "androidx.media3:media3-session:1.4.0"
    
  3. Zamień MediaSessionCompat na androidx.media3.session.MediaSession

  4. Na stronie kodu, w której masz utworzoną starszą wersję MediaSessionCompat, użyj kodu androidx.media3.session.MediaSession.Builder, aby utworzyć MediaSession. Przekaż odtwarzacz, by utworzyć kreator sesji.

    val player = ExoPlayer.Builder(context).build()
    mediaSession = MediaSession.Builder(context, player)
        .setSessionCallback(MySessionCallback())
        .build()
    
  5. Zaimplementuj MySessionCallback zgodnie z wymaganiami aplikacji. Nie jest to jednak wymagane. Jeśli jeśli chcesz zezwolić kontrolerom na dodawanie elementów multimedialnych do odtwarzacza, MediaSession.Callback.onAddMediaItems() Obsługuje różne bieżące i starszych metod interfejsu API, które dodają elementy multimedialne do odtwarzacza w celu wstecznie. Obejmuje to m.in.: MediaController.set/addMediaItems() metody kontrolera Media3, oraz TransportControls.prepareFrom*/playFrom* starszej wersji interfejsu API. Przykładowa implementacja interfejsu onAddMediaItems może znajdziesz w PlaybackService aplikacji demonstracyjnej sesji.

  6. 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 wdrożone w funkcji MediaSessionConnector.

Łącznik sesji MediaSessionAndroidX 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

Przenieś MediaBrowserService do MediaLibraryService

AndroidX Media3 wprowadza interfejs MediaLibraryService, który zastępuje MediaBrowserServiceCompat Dokument JavaDoc typu MediaLibraryService i jego element nadrzędny klasa MediaSessionService stanowi dobre wprowadzenie do interfejsu API oraz asynchroniczny model programowania usługi.

Aplikacja MediaLibraryService jest zgodna wstecznie z MediaBrowserService Aplikacja kliencka, która używa MediaBrowserCompat lub MediaControllerCompat, będzie nadal działać bez zmian w kodzie po połączeniu do: MediaLibraryService. Dla klienta jasne jest, czy aplikacja jest za pomocą modelu MediaLibraryService lub starszej wersji MediaBrowserServiceCompat.

Diagram komponentu aplikacji z usługą, aktywnością i aplikacjami zewnętrznymi.
Rysunek 1. Omówienie komponentu aplikacji do multimediów
    ,
  1. Aby zgodność wsteczna działała, zarejestruj obie usługi z usługą w interfejsie AndroidManifest.xml. W ten sposób Klient znajduje 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>
    
  2. W pliku build.gradle, w którym przechowujesz zależności, dodaj parametr zależność wdrożenia od modułu sesji AndroidX Media3 oraz usuń starszą zależność:

    implementation "androidx.media3:media3-session:1.4.0"
    
  3. Zmień swoją usługę tak, aby dziedziczyła z elementu MediaLibraryService, a nie z MediaBrowserService Jak wspomnieliśmy wcześniej, urządzenie MediaLibraryService jest zgodne ze starszą wersją. MediaBrowserService W związku z tym szerszy interfejs API, w którym dana usługa jest oferowane klientom pozostaje bez zmian. Możliwe więc, że aplikacja zachowa większość logiki wymaganej do wdrożenia MediaBrowserService i dostosuj ją do nowego środowiska: MediaLibraryService.

    Główne różnice w porównaniu ze starszą wersją MediaBrowserServiceCompat są takie:

    • Zaimplementuj metody cyklu życia usługi: metody, które muszą do zastąpienia w samej usłudze to onCreate/onDestroy, gdzie aplikacja przydziela/uwalnia sesję biblioteki, odtwarzacz i inne elementy i zasobami Google Cloud. Oprócz standardowych metod cyklu życia usługi aplikacja musi zastąpić wartość onGetSession(MediaSession.ControllerInfo), aby zwrócić MediaLibrarySession, który powstał w onCreate.

    • Implement MediaLibraryService.MediaLibrarySessionCallback: kompilacja sesja wymaga MediaLibraryService.MediaLibrarySessionCallback, który stosuje rzeczywiste metody API domeny. Dlatego zamiast zastępowania metod interfejsu API starszej wersji usługi, zastąpisz metody MediaLibrarySession.Callback.

      Wywołanie zwrotne jest następnie używane do utworzenia MediaLibrarySession:

      mediaLibrarySession =
            MediaLibrarySession.Builder(this, player, MySessionCallback())
               .build()
      

      Znajdź w nim pełny interfejs API MediaLibrarySessionCallback. dokumentacji.

    • Implementacja MediaSession.Callback.onAddMediaItems(): wywołanie zwrotne Serw: onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) różne obecne i starsze metody interfejsu API, które dodają elementy multimedialne do odtwarzacza. do odtwarzania w sposób zgodny wstecznie. Obejmuje to m.in.: MediaController.set/addMediaItems() metod kontrolera Media3, oraz TransportControls.prepareFrom*/playFrom* starszej wersji interfejsu API. Przykładowa implementacja wywołania zwrotnego może znajdziesz w PlaybackService aplikacji demonstracyjnej sesji.

    • AndroidX Media3 korzysta z interfejsu androidx.media3.common.MediaItem z Media BrowserCompat.MediaItem i MediaMetadataCompat. Części kodu powiązanego ze starszymi klasami musisz odpowiednio zmienić. lub zmapuj na interfejs Media3 MediaItem.

    • Ogólny model programowania asynchronicznego zmienił się na Futures w kontrastuje z podejściem Result, MediaBrowserServiceCompat. Implementacja usługi może zwrócić błąd asynchronicznie ListenableFuture zamiast odłączać wynik lub zwraca natychmiastową przyszłość, aby zwrócić bezpośrednio wartość.

Usunięcie PlayerPowiadomienieManagera

MediaLibraryService automatycznie obsługuje powiadomienia o multimediach oraz PlayerNotificationManager można usunąć za pomocą MediaLibraryService lub MediaSessionService.

Aplikacja może dostosować powiadomienie, ustawiając niestandardowe MediaNotification.Provider w: onCreate(), która zastępuje DefaultMediaNotificationProvider. MediaLibraryService zajmie się uruchamianie usługi na pierwszym planie zgodnie z wymaganiami.

Dzięki zastąpieniu ustawienia MediaLibraryService.updateNotification() aplikacja może wykonać dalsze działania będziesz mieć uprawnienia do publikowania powiadomień oraz uruchamiania/zatrzymywania usługi w na pierwszym planie zgodnie z wymaganiami.

Migracja kodu klienta przy użyciu przeglądarki Media Browser

W przypadku AndroidX Media3 w MediaBrowser implementuje interfejs MediaController/Player udostępnia interfejsy API i może być wykorzystywane do sterowania odtwarzaniem multimediów poza przeglądaniem multimediów bibliotece. Gdyby trzeba było utworzyć atrybuty MediaBrowserCompat i MediaControllerCompat, możesz zrobić to samo, używając tylko MediaBrowser w Media3.

Można utworzyć MediaBrowser i poczekać na połączenie z ustanawianie usługi:

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)
}

Zwróć uwagę na: Sterowanie odtwarzaniem w trakcie sesji multimediów aby dowiedzieć się, jak utworzyć klucz MediaController do sterowania odtwarzaniem w w tle.

Dalsze kroki i czyszczenie

Błędy niestabilnego interfejsu API

Po migracji do Media3 mogą pojawić się błędy lint dotyczące niestabilnych zastosowań interfejsu API. Te interfejsy API są bezpieczne w użyciu, a błędy lintowania są efektem ubocznym naszego nowego rozwiązania gwarantuje zgodność z obiektami binarnymi. Jeśli nie jest wymagany rygorystyczny kod binarny zgodności, te błędy można bezpiecznie powstrzymać za pomocą funkcji @OptIn adnotacja.

Tło

Ani ExoPlayer w wersji 1, ani 2 nie zapewniał ścisłych gwarancji zgodności plików binarnych dostęp do biblioteki między kolejnymi wersjami. Interfejs API ExoPlayer duży rozmiar, dzięki czemu aplikacje mogą dostosowywać niemal każdy aspekt odtwarzania. W kolejnych wersjach ExoPlayer od czasu do czasu pojawiał się symbol zmiany nazw lub inne zmiany powodujące niezgodność (np. nowe wymagane metody w interfejsach). W w większości przypadków te uszkodzenia zostały zniwelowane dzięki nowemu symbolowi oraz wycofanie starego symbolu na kilka wersji, aby umożliwić programistom czas na migrację wykorzystania, ale nie zawsze było to możliwe.

Te nieistotne zmiany spowodowały 2 problemy dla użytkowników ExoPlayer v1 oraz biblioteki w wersji 2:

  1. Przejście z wersji ExoPlayer na wersję ExoPlayer może spowodować zatrzymanie kompilacji kodu.
  2. Aplikacja, która bazowała na ExoPlayer zarówno bezpośrednio, jak i średnio musi zapewnić tę samą wersję obu zależności, W przeciwnym razie niezgodności binarne mogą spowodować awarię środowiska wykonawczego.

Ulepszenia w Media3

Media3 gwarantuje zgodność plików binarnych dla podzbioru powierzchni interfejsu API. części, które nie gwarantują zgodności binarnej, są oznaczone znakiem @UnstableApi. Aby wyraźnie podkreślić to rozróżnienie, zastosowania niestabilnych wersji Symbole interfejsu API generują błąd lint, chyba że mają adnotację @OptIn.

Po migracji z ExoPlayer v2 do Media3 możesz zauważyć wiele niestabilnych interfejsów API lintowania. Może to sprawiać wrażenie, że Media3 jest „mniej stabilne”. niż ExoPlayer wersja 2. To nieprawda. „Niestabilne” części interfejsu Media3 API są takie same poziom stabilności całej powierzchni interfejsu API ExoPlayer v2 oraz gwarancje stabilnej powierzchni interfejsu Media3 API nie są dostępne w przypadku ExoPlayer v2 na stronie wszystko. Różnica polega na tym, że błąd lintowania informuje teraz o różnych i stabilności.

Obsługa niestabilnych błędów lintowania interfejsu API

Zapoznaj się z sekcją rozwiązywania problemów z błędami lintowania, aby dowiedzieć się, jak opisanie przypadków użycia niestabilnych interfejsów API w językach Java i Kotlin za pomocą parametru @OptIn.

Wycofane interfejsy API

Możesz zauważyć, że wywołania wycofanych interfejsów API w Androidzie są przekreślone Studio. Zalecamy zastąpienie takich połączeń odpowiednią alternatywą. Najedź kursorem na ten symbol, aby zobaczyć dokument JavaDoc informujący o tym, którego interfejsu API użyć.

Zrzut ekranu: jak wyświetlić dokument JavaDoc z alternatywną, wycofaną metodą
Rysunek 3. Etykietka JavaDoc w Android Studio sugeruje alternatywę dla dowolnego wycofanego symbolu.

Przykładowe fragmenty kodu i aplikacje demonstracyjne

  • Aplikacja demonstracyjna sesji na AndroidaX Media3 (na urządzenia mobilne i Wear OS)
    • Działania niestandardowe
    • Powiadomienie w interfejsie systemowym, MediaButton/BT
    • Sterowanie odtwarzaniem w Asystencie Google
  • UAMP: Android Media Player (branch media3) (urządzenia mobilne, system AutomotiveOS)
    • Powiadomienie w interfejsie systemu, MediaButton/BT, wznowienie odtwarzania
    • Sterowanie odtwarzaniem w Asystencie Google/Wear OS
    • AutomotiveOS: niestandardowe polecenie i logowanie