Las apps que actualmente usan la biblioteca independiente com.google.android.exoplayer2 y androidx.media deberían migrar a androidx.media3. Usa la secuencia de comandos de migración para migrar los archivos de compilación de Gradle, los archivos de origen de Java y Kotlin, y los archivos de diseño XML de ExoPlayer 2.19.1 a AndroidX Media3 1.1.1.
Descripción general
Antes de migrar, revisa las siguientes secciones para obtener más información sobre los beneficios de las APIs nuevas, las APIs que se deben migrar y los requisitos previos que debe cumplir el proyecto de tu app.
Por qué migrar a Jetpack Media3
- Es el nuevo hogar de ExoPlayer, mientras que
com.google.android.exoplayer2se descontinuó. - Accede a la API de Player en todos los componentes y procesos con
MediaBrowser/MediaController. - Usa las capacidades extendidas de la API de
MediaSessionyMediaController. - Anuncia las capacidades de reproducción con un control de acceso detallado.
- Simplifica tu app quitando
MediaSessionConnectoryPlayerNotificationManager. - Retrocompatible con las APIs de cliente de media-compat (
MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat)
APIs de Media para migrar a Media3 de AndroidX
- ExoPlayer y sus extensiones
Esto incluye todos los módulos del proyecto de ExoPlayer heredado, excepto el módulo mediasession, que se descontinuó. Las apps o los módulos que dependen de paquetes encom.google.android.exoplayer2se pueden migrar con la secuencia de comandos de migración. - MediaSessionConnector (según los paquetes
androidx.media.*deandroidx.media:media:1.4.3+)
QuitaMediaSessionConnectory usaandroidx.media3.session.MediaSessionen su lugar. - MediaBrowserServiceCompat (según los paquetes
androidx.media.*deandroidx.media:media:1.4.3+)
Migra las subclases deandroidx.media.MediaBrowserServiceCompataandroidx.media3.session.MediaLibraryServicey el código que usaMediaBrowserCompat.MediaItemaandroidx.media3.common.MediaItem. - MediaBrowserCompat (según los paquetes
android.support.v4.media.*deandroidx.media:media:1.4.3+)
Migra el código del cliente conMediaBrowserCompatoMediaControllerCompatpara usarandroidx.media3.session.MediaBrowserconandroidx.media3.common.MediaItem.
Requisitos previos
Asegúrate de que tu proyecto esté bajo control de código fuente
Asegúrate de poder revertir con facilidad los cambios que aplican las herramientas de migración con secuencias de comandos. Si aún no tienes tu proyecto bajo control de código fuente, este es un buen momento para comenzar. Si, por algún motivo, no quieres hacerlo, crea una copia de seguridad de tu proyecto antes de comenzar la migración.
Actualiza tu app
Te recomendamos que actualices tu proyecto para usar la versión más reciente de la biblioteca de ExoPlayer y quites las llamadas a métodos obsoletos. Si quieres usar la secuencia de comandos para la migración, debes hacer coincidir la versión que estás actualizando con la versión que controla la secuencia de comandos.
Aumenta el valor de compileSdkVersion de tu app a 32 como mínimo.
Actualiza Gradle y el complemento de Gradle para Android Studio a una versión reciente que funcione con las dependencias actualizadas que se mencionaron anteriormente. Por ejemplo:
- Versión del complemento de Android para Gradle: 7.1.0
- Versión de Gradle: 7.4
Reemplaza todas las declaraciones de importación de comodines que usen un asterisco (*) y usa declaraciones de importación completamente calificadas: borra las declaraciones de importación de comodines y usa Android Studio para importar las declaraciones completamente calificadas (F2 - Alt/Intro, F2 - Alt/Intro, etcétera).
Migra de
com.google.android.exoplayer2.PlayerViewacom.google.android.exoplayer2.StyledPlayerView. Esto es necesario porque no hay un equivalente acom.google.android.exoplayer2.PlayerViewen Media3 de AndroidX.
Migra ExoPlayer con compatibilidad con secuencias de comandos
La secuencia de comandos facilita el cambio de com.google.android.exoplayer2 a la nueva
estructura de paquetes y módulos en androidx.media3. La secuencia de comandos aplica algunas verificaciones de validación en tu proyecto y muestra advertencias si la validación falla.
De lo contrario, aplica las asignaciones de clases y paquetes con nombres cambiados en los recursos de un proyecto de Gradle para Android escrito en Java o 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
Usa la secuencia de comandos de migración
Descarga la secuencia de comandos de migración de la etiqueta del proyecto de ExoPlayer en GitHub que corresponda a la versión a la que actualizaste tu app:
curl -o media3-migration.sh \ "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"Haz que la secuencia de comandos sea ejecutable:
chmod 744 media3-migration.shEjecuta la secuencia de comandos con
--helppara obtener información sobre las opciones.Ejecuta la secuencia de comandos con
-lpara enumerar el conjunto de archivos que se seleccionaron para la migración (usa-fpara forzar la lista sin advertencias):./media3-migration.sh -l -f /path/to/gradle/project/rootEjecuta la secuencia de comandos con
-mpara asignar paquetes, clases y módulos a Media3. Si ejecutas la secuencia de comandos con la opción-m, se aplicarán los cambios a los archivos seleccionados.- Detenerse en el error de validación sin realizar cambios
./media3-migration.sh -m /path/to/gradle/project/root- Ejecución forzada
Si la secuencia de comandos encuentra un incumplimiento de los requisitos previos, se puede forzar la migración con la marca
-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
Completa estos pasos manuales después de ejecutar la secuencia de comandos con la opción -m:
- Verifica cómo la secuencia de comandos cambió tu código: Usa una herramienta de diferencias y corrige los posibles problemas (considera informar un error si crees que la secuencia de comandos tiene un problema general que se introdujo sin pasar la opción
-f). - Compila el proyecto: Usa
./gradlew clean buildo, en Android Studio, elige File > Sync Project with Gradle Files, luego Build > Clean project y, por último, Build > Rebuild project (supervisa la compilación en la pestaña "Build - Build Output" de Android Studio).
Pasos de seguimiento recomendados:
- Resuelve la habilitación de errores relacionados con el uso de APIs inestables.
- Reemplaza las llamadas a la API obsoletas: Usa la API de reemplazo sugerida. Mantén el puntero sobre la advertencia en Android Studio y consulta el JavaDoc del símbolo obsoleto para saber qué usar en lugar de una llamada determinada.
- Ordena las declaraciones de importación: Abre el proyecto en Android Studio, haz clic con el botón derecho en un nodo de carpeta de paquete en el visor de proyectos y elige Optimize imports en los paquetes que contienen los archivos de origen modificados.
Reemplaza MediaSessionConnector con androidx.media3.session.MediaSession.
En el mundo heredado de MediaSessionCompat, MediaSessionConnector era responsable de sincronizar el estado del reproductor con el estado de la sesión y recibir comandos de los controladores que necesitaban delegación a los métodos de reproductor adecuados. Con AndroidX Media3, esto lo hace directamente MediaSession sin necesidad de un conector.
Quita todas las referencias y el uso de MediaSessionConnector: Si usaste la secuencia de comandos automatizada para migrar clases y paquetes de ExoPlayer, es probable que la secuencia de comandos haya dejado tu código en un estado no compilable con respecto a
MediaSessionConnectorque no se puede resolver. Android Studio te mostrará el código dañado cuando intentes compilar o iniciar la app.En el archivo
build.gradleen el que mantienes tus dependencias, agrega una dependencia de implementación al módulo de sesión de AndroidX Media3 y quita la dependencia heredada:implementation "androidx.media3:media3-session:1.11.1"Reemplaza
MediaSessionCompatporandroidx.media3.session.MediaSession.En el sitio del código en el que creaste el
MediaSessionCompatheredado, usaandroidx.media3.session.MediaSession.Builderpara compilar unMediaSession. Pasa el reproductor para construir el compilador de sesiones.Kotlin
val player = ExoPlayer.Builder(context).build() mediaSession = MediaSession.Builder(context, player).setCallback(MySessionCallback()).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); mediaSession = new MediaSession.Builder(context, player).setCallback(new MySessionCallback()).build();
Implementa
MySessionCallbacksegún lo requiera tu app (opcional). Si quieres permitir que los controladores agreguen elementos multimedia al reproductor, implementaMediaSession.Callback.onAddMediaItems(). Ofrece varios métodos de API actuales y heredados que agregan elementos multimedia al reproductor para su reproducción de forma retrocompatible. Esto incluye los métodosMediaController.set/addMediaItems()del controlador de Media3, así como los métodosTransportControls.prepareFrom*/playFrom*de la API heredada. Puedes encontrar una implementación de muestra deonAddMediaItemsen elPlaybackServicede la app de demostración de la sesión.Libera la sesión multimedia en el sitio del código en el que destruiste la sesión antes de la migración:
Kotlin
mediaSession?.run { player.release() release() mediaSession = null }
Java
if (mediaSession != null) { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; }
Funcionalidad de MediaSessionConnector en Media3
En la siguiente tabla, se muestran las APIs de Media3 que controlan la funcionalidad que antes se implementaba en MediaSessionConnector.
| MediaSessionConnector | AndroidX Media3 |
|---|---|
CustomActionProvider |
MediaSession.Callback.onCustomCommand()/
MediaSession.setMediaButtonPreferences() |
PlaybackPreparer |
MediaSession.Callback.onAddMediaItems()
(prepare() se llama de forma interna)
|
QueueNavigator |
ForwardingSimpleBasePlayer |
QueueEditor |
MediaSession.Callback.onAddMediaItems() |
RatingCallback |
MediaSession.Callback.onSetRating() |
PlayerNotificationManager |
DefaultMediaNotificationProvider/
MediaNotification.Provider |
Migra MediaBrowserService a MediaLibraryService
AndroidX Media3 presenta MediaLibraryService, que reemplaza a MediaBrowserServiceCompat. El JavaDoc de MediaLibraryService y su superclase MediaSessionService proporcionan una buena introducción a la API y al modelo de programación asíncrona del servicio.
La MediaLibraryService es retrocompatible con la
MediaBrowserService. Una app cliente que usa MediaBrowserCompat o
MediaControllerCompat sigue funcionando sin cambios en el código cuando se conecta
a un MediaLibraryService. Para un cliente, es transparente si tu app usa un MediaLibraryService o un MediaBrowserServiceCompat heredado.
Para que funcione la retrocompatibilidad, debes registrar ambas interfaces de servicio con tu servicio en el
AndroidManifest.xml. De esta manera, un cliente encuentra tu servicio por la interfaz de servicio requerida:<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>En el archivo
build.gradleen el que mantienes tus dependencias, agrega una dependencia de implementación al módulo de sesión de AndroidX Media3 y quita la dependencia heredada:implementation "androidx.media3:media3-session:1.11.1"Cambia tu servicio para que herede de un
MediaLibraryServiceen lugar deMediaBrowserService. Como se mencionó antes,MediaLibraryServicees compatible con elMediaBrowserServiceheredado. Por lo tanto, la API más amplia que el servicio ofrece a los clientes sigue siendo la misma. Por lo tanto, es probable que una app pueda conservar la mayor parte de la lógica necesaria para implementarMediaBrowserServicey adaptarla al nuevoMediaLibraryService.Las principales diferencias en comparación con la versión heredada de
MediaBrowserServiceCompatson las siguientes:Implementa los métodos del ciclo de vida del servicio: Los métodos que se deben anular en el servicio son
onCreate/onDestroy, en los que una app asigna o libera la sesión de la biblioteca, el reproductor y otros recursos. Además de los métodos estándar del ciclo de vida del servicio, una app debe anularonGetSession(MediaSession.ControllerInfo)para devolver elMediaLibrarySessionque se compiló enonCreate.Implementa MediaLibraryService.MediaLibrarySessionCallback: Para compilar una sesión, se requiere un
MediaLibraryService.MediaLibrarySessionCallbackque implemente los métodos reales de la API de dominio. Por lo tanto, en lugar de anular los métodos de la API del servicio heredado, anularás los métodos deMediaLibrarySession.Callback.Luego, la devolución de llamada se usa para compilar el
MediaLibrarySession:Kotlin
mediaLibrarySession = MediaLibrarySession.Builder(context, player, MySessionCallback()).build()
Java
mediaLibrarySession = new MediaLibrarySession.Builder(context, player, new MySessionCallback()).build();
Busca la API completa de MediaLibrarySessionCallback en la documentación de la API.
Implementa
MediaSession.Callback.onAddMediaItems(): La devolución de llamadaonAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>)entrega varios métodos de API actuales y heredados que agregan elementos multimedia al reproductor para la reproducción de forma retrocompatible. Esto incluye los métodosMediaController.set/addMediaItems()del controlador de Media3, así como los métodosTransportControls.prepareFrom*/playFrom*de la API heredada. Puedes encontrar una implementación de muestra de la devolución de llamada en elPlaybackServicede la app de demostración de la sesión.AndroidX Media3 usa
androidx.media3.common.MediaItemen lugar de MediaBrowserCompat.MediaItem y MediaMetadataCompat. Las partes de tu código vinculadas a las clases heredadas deben cambiarse según corresponda o asignarse aMediaItemde Media3.El modelo general de programación asíncrona cambió a
Futures, en contraste con el enfoque deResultdesconectable deMediaBrowserServiceCompat. La implementación de tu servicio puede mostrar unListenableFutureasíncrono en lugar de separar un resultado o mostrar un Future inmediato para devolver un valor directamente.
Quita PlayerNotificationManager
MediaLibraryService admite notificaciones de contenido multimedia automáticamente y PlayerNotificationManager se puede quitar cuando se usa MediaLibraryService o MediaSessionService.
Una app puede personalizar la notificación configurando un MediaNotification.Provider personalizado en onCreate() que reemplace el DefaultMediaNotificationProvider. Luego, MediaLibraryService se encarga de iniciar el servicio en primer plano según sea necesario.
Anulando MediaLibraryService.updateNotification(), una app puede asumir la propiedad total de la publicación de una notificación y el inicio o la detención del servicio en primer plano según sea necesario.
Migra el código de cliente con un MediaBrowser
Con Media3 de AndroidX, un MediaBrowser implementa las interfaces MediaController/Player y se puede usar para controlar la reproducción de contenido multimedia, además de explorar la biblioteca de contenido multimedia. Si tuviste que crear un MediaBrowserCompat y un MediaControllerCompat en el mundo heredado, puedes hacer lo mismo usando solo el MediaBrowser en Media3.
Se puede compilar un MediaBrowser y esperar a que se establezca la conexión con el servicio:
Kotlin
scope.launch { val sessionToken = SessionToken(context, ComponentName(context, "MusicService")) browser = MediaBrowser.Builder(context, sessionToken) .setListener(BrowserListener()) .buildAsync() .await() }
Java
SessionToken sessionToken = new SessionToken(context, new ComponentName(context, "MusicService")); ListenableFuture<MediaBrowser> browserFuture = new MediaBrowser.Builder(context, sessionToken) .setListener(new BrowserListener()) .buildAsync();
Consulta Controla la reproducción en la sesión multimedia para aprender a crear un MediaController que controle la reproducción en segundo plano.
Pasos adicionales y limpieza
Errores de API inestable
Después de migrar a Media3, es posible que veas errores de lint sobre usos de APIs inestables.
Estas APIs son seguras de usar, y los errores de lint son un subproducto de nuestras nuevas garantías de compatibilidad binaria. Si no necesitas una compatibilidad binaria estricta, estos errores se pueden suprimir de forma segura con una anotación @OptIn.
Fondo
Ni ExoPlayer v1 ni v2 proporcionaban garantías estrictas sobre la compatibilidad binaria de la biblioteca entre versiones posteriores. La plataforma de la API de ExoPlayer es muy grande por diseño, para permitir que las apps personalicen casi todos los aspectos de la reproducción. En las versiones posteriores de ExoPlayer, se introducían ocasionalmente cambios de nombre de símbolos o cambios rotundos (p.ej., nuevos métodos obligatorios en las interfaces). En la mayoría de los casos, estas fallas se mitigaron con la introducción del símbolo nuevo junto con la baja del símbolo anterior durante algunas versiones, para darles tiempo a los desarrolladores de migrar sus usos, pero esto no siempre fue posible.
Estos cambios rotundos generaron dos problemas para los usuarios de las bibliotecas de ExoPlayer v1 y v2:
- Una actualización de la versión de ExoPlayer podría hacer que el código deje de compilarse.
- Una app que dependía de ExoPlayer de forma directa y a través de una biblioteca intermedia debía garantizar que ambas dependencias fueran de la misma versión; de lo contrario, las incompatibilidades binarias podían provocar fallas en el tiempo de ejecución.
Mejoras en Media3
Media3 garantiza la compatibilidad binaria para un subconjunto de la plataforma de la API. Las partes que no garantizan la compatibilidad binaria se marcan con @UnstableApi. Para que esta distinción sea clara, los usos de símbolos de API inestables generan un error de lint, a menos que se anoten con @OptIn.
Después de migrar de ExoPlayer v2 a Media3, es posible que veas muchos errores de lint de la API inestable. Esto puede hacer que parezca que Media3 es "menos estable" que ExoPlayer v2. Sin embargo, este no es el caso. Las partes "inestables" de la API de Media3 tienen el mismo nivel de estabilidad que toda la plataforma de la API de ExoPlayer v2, y las garantías de la plataforma de la API de Media3 estable no están disponibles en ExoPlayer v2. La diferencia es que ahora un error de lint te alerta sobre los diferentes niveles de estabilidad.
Controla los errores de lint de la API inestable
Consulta la sección de solución de problemas de estos errores de lint para obtener detalles sobre cómo anotar los usos de Java y Kotlin de las APIs inestables con @OptIn.
API obsoletas
Es posible que notes que las llamadas a las APIs obsoletas están tachadas en Android Studio. Te recomendamos que reemplaces esas llamadas por la alternativa adecuada. Coloca el cursor sobre el símbolo para ver el JavaDoc que indica qué API usar en su lugar.
Muestras de código y apps de demostración
- App de demostración de sesiones de AndroidX Media3 (dispositivos móviles y Wear OS)
- Acciones personalizadas
- Notificación de la IU del sistema, MediaButton/BT
- Control de reproducción de Asistente de Google
- UAMP: Android Media Player (rama media3) (dispositivos móviles, AutomotiveOS)
- Notificación de la IU del sistema, MediaButton/BT, reanudación de la reproducción
- Control de reproducción de Asistente de Google y Wear OS
- AutomotiveOS: Comando personalizado y acceso