Las apps que actualmente usan la biblioteca independiente com.google.android.exoplayer2
y androidx.media
deben migrar a androidx.media3
. Usa la secuencia de comandos de migración para migrar archivos de compilación de Gradle, archivos fuente de Java y Kotlin, y 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 nuevas APIs, las APIs que se migrarán y los requisitos previos que debe cumplir el proyecto de tu app.
Por qué migrar a Jetpack Media3
- Es la nueva página principal de ExoPlayer, mientras que
com.google.android.exoplayer2
está descontinuada. - Accede a la API del reproductor en todos los componentes o procesos con
MediaBrowser
/MediaController
. - Utiliza las capacidades extendidas de las APIs de
MediaSession
yMediaController
. - Anuncia las capacidades de reproducción con el control de acceso detallado.
- Simplifica tu app quitando
MediaSessionConnector
yPlayerNotificationManager
. - Retrocompatible con las APIs de cliente media-compat (
MediaBrowserCompat
/MediaControllerCompat
/MediaMetadataCompat
)
APIs de contenido multimedia para migrar a AndroidX Media3
- ExoPlayer y sus extensiones
Esto incluye todos los módulos del proyecto de ExoPlayer heredado, excepto el módulo mediasession que está descontinuado. Las apps o los módulos que dependen de los paquetes encom.google.android.exoplayer2
se pueden migrar con la secuencia de comandos de migración. - MediaSessionConnector (según los paquetes
androidx.media.*
deandroidx.media:media:1.4.3+
)
Quita elMediaSessionConnector
y usaandroidx.media3.session.MediaSession
en su lugar. - MediaBrowserServiceCompat (según los paquetes
androidx.media.*
deandroidx.media:media:1.4.3+
)
Migra las subclases deandroidx.media.MediaBrowserServiceCompat
aandroidx.media3.session.MediaLibraryService
y el código que usaMediaBrowserCompat.MediaItem
aandroidx.media3.common.MediaItem
. - MediaBrowserCompat (según los paquetes
android.support.v4.media.*
deandroidx.media:media:1.4.3+
)
Migra el código de cliente conMediaBrowserCompat
oMediaControllerCompat
para usarandroidx.media3.session.MediaBrowser
conandroidx.media3.common.MediaItem
.
Requisitos previos
Asegúrate de que tu proyecto esté bajo el control del código fuente
Asegúrate de poder revertir con facilidad los cambios aplicados por las herramientas de migración con secuencia de comandos. Si aún no tienes tu proyecto bajo control del código fuente, ahora es un buen momento para comenzar con él. Si por alguna razón no quieres hacerlo, crea una copia de seguridad de tu proyecto antes de comenzar la migración.
Actualiza tu app
Te recomendamos actualizar el proyecto para usar la versión más reciente de la biblioteca de ExoPlayer y quitar las llamadas a los métodos obsoletos. Si deseas usar la secuencia de comandos para la migración, debes hacer coincidir la versión a la que deseas actualizar con la versión que controla la secuencia de comandos.
Aumenta la compileSdkVersion de tu app a, al menos, 32.
Actualiza Gradle y el complemento de Gradle para Android Studio a una versión reciente que funcione con las dependencias actualizadas anteriormente. Por ejemplo:
- Versión del complemento de Android para Gradle: 7.1.0
- Versión de Gradle: 7.4
Reemplaza todas las sentencias de importación de comodines que usan un asterisco (*) y usa declaraciones de importación completamente calificadas. Borra las sentencias de importación de comodines y usa Android Studio para importar las declaraciones completamente calificadas (F2: Alt/Intro, F2: Alt/Intro, etc.).
Migra de
com.google.android.exoplayer2.PlayerView
acom.google.android.exoplayer2.StyledPlayerView
. Esto es necesario porque no hay equivalente acom.google.android.exoplayer2.PlayerView
en AndroidX Media3.
Cómo migrar ExoPlayer con compatibilidad para secuencias de comandos
La secuencia de comandos facilita el cambio de com.google.android.exoplayer2
al nuevo paquete y estructura de módulo en androidx.media3
. La secuencia de comandos aplica algunas verificaciones de validación en tu proyecto y, luego, imprime advertencias si falla la validación.
De lo contrario, aplica las asignaciones de clases y paquetes con nombres nuevos 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 correspondiente 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.sh
Ejecuta la secuencia de comandos con
--help
para conocer las opciones.Ejecuta la secuencia de comandos con
-l
para enumerar el conjunto de archivos seleccionados para la migración (usa-f
si quieres forzar la lista sin advertencias):./media3-migration.sh -l -f /path/to/gradle/project/root
Ejecuta la secuencia de comandos con
-m
para 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.- Detener 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 una infracción de los requisitos previos, la migración se puede forzar 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 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 build
o, en Android Studio, selecciona File > Sync Project with Gradle Files, Build > Clean project y, luego, Build > Rebuild project (supervisa tu compilación en la pestaña Build - Build Output de Android Studio).
Pasos de seguimiento recomendados:
- Resolver la aceptación de errores relacionados con el uso de APIs inestables
- Reemplazar las llamadas a la API obsoletas: Usa la API de reemplazo sugerida. Mantén el cursor sobre la advertencia en Android Studio y consulta el JavaDoc del símbolo obsoleto para averiguar 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 paquetes en el visor del proyecto y selecciona Optimize imports en los paquetes que contienen los archivos fuente modificados.
Reemplaza MediaSessionConnector
con androidx.media3.session.MediaSession
.
En el mundo heredado de MediaSessionCompat
, MediaSessionConnector
era responsable de sincronizar el estado del jugador con el de la sesión y recibir comandos de los controladores que necesitaban delegación a los métodos del jugador adecuados. Con AndroidX Media3, MediaSession
lo hace directamente sin necesidad de un conector.
Quita todas las referencias y el uso de MediaSessionConnector: Si usaste la secuencia de comandos automatizada para migrar las clases y los paquetes de ExoPlayer, es probable que la secuencia de comandos haya dejado tu código en un estado no compilable con respecto a la
MediaSessionConnector
que no se puede resolver. Android Studio te mostrará el código dañado cuando intentes compilar o iniciar la app.En el archivo
build.gradle
, en 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.3.1"
Reemplaza
MediaSessionCompat
porandroidx.media3.session.MediaSession
.En el sitio de código en el que creaste el
MediaSessionCompat
heredado, usaandroidx.media3.session.MediaSession.Builder
para compilar unMediaSession
. Pasa el jugador para construir el compilador de sesiones.val player = ExoPlayer.Builder(context).build() mediaSession = MediaSession.Builder(context, player) .setSessionCallback(MySessionCallback()) .build()
Implementa
MySessionCallback
según lo requiera tu app. Esto es opcional. Si quieres permitir que los controles agreguen elementos multimedia al reproductor, implementaMediaSession.Callback.onAddMediaItems()
. Entrega varios métodos de API actuales y heredados que agregan elementos multimedia al reproductor para reproducirlos de manera 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 deonAddMediaItems
en el elementoPlaybackService
de la app de demostración de la sesión.Libera la sesión multimedia en el sitio del código donde destruiste la sesión antes de la migración:
mediaSession?.run { player.release() release() mediaSession = null }
Funcionalidad MediaSessionConnector
en Media3
En la siguiente tabla, se muestran las APIs de Media3 que controlan la funcionalidad implementada anteriormente en MediaSessionConnector
.
MediaSessionConnector | AndroidX Media3 |
---|---|
CustomActionProvider |
MediaSession.Callback.onCustomCommand()/
MediaSession.setCustomLayout() |
PlaybackPreparer |
MediaSession.Callback.onAddMediaItems() (prepare() se llama de forma interna)
|
QueueNavigator |
ForwardingPlayer |
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íncrono del servicio.
MediaLibraryService
es retrocompatible con MediaBrowserService
. Una app cliente que usa MediaBrowserCompat
o MediaControllerCompat
continúa funcionando sin cambios de código cuando se conecta a MediaLibraryService
. Para un cliente, es transparente si tu app usa un MediaLibraryService
o un MediaBrowserServiceCompat
heredado.
![Diagrama de componentes de la app con el servicio, la actividad y las apps externas.](https://developer.android.com/static/media/images/overview.png?authuser=8&hl=es)
Para que la retrocompatibilidad funcione, debes registrar ambas interfaces de servicio con tu servicio en
AndroidManifest.xml
. De esta manera, un cliente encuentra tu servicio mediante 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.gradle
, en 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.3.1"
Cambia tu servicio para que herede de un
MediaLibraryService
en lugar deMediaBrowserService
. Como se mencionó antes,MediaLibraryService
es compatible con elMediaBrowserService
heredado. Por lo tanto, la API más amplia que ofrece el servicio a los clientes sigue siendo la misma. Por lo tanto, es probable que una app pueda mantener la mayor parte de la lógica necesaria para implementarMediaBrowserService
y adaptarlo al nuevoMediaLibraryService
.Las principales diferencias en comparación con la
MediaBrowserServiceCompat
heredada son las siguientes:Implementa los métodos de ciclo de vida del servicio: Los métodos que se deben anular en el servicio son
onCreate/onDestroy
, en el que una app asigna o libera la sesión de biblioteca, el reproductor y otros recursos. Además de los métodos estándar de ciclo de vida del servicio, una app debe anularonGetSession(MediaSession.ControllerInfo)
para mostrar elMediaLibrarySession
que se compiló enonCreate
.Implementa MediaLibraryService.MediaLibrarySessionCallback: La compilación de una sesión requiere una
MediaLibraryService.MediaLibrarySessionCallback
que implemente los métodos reales de la API del dominio. Por lo tanto, en lugar de anular los métodos de la API del servicio heredado, deberás anular los métodos deMediaLibrarySession.Callback
.Luego, se usa la devolución de llamada para compilar el
MediaLibrarySession
:mediaLibrarySession = MediaLibrarySession.Builder(this, player, MySessionCallback()) .build()
Encuentra 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 reproducirlos de manera 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 un ejemplo de implementación de la devolución de llamada en elPlaybackService
de la app de demostración de la sesión.AndroidX Media3 usa
androidx.media3.common.MediaItem
en lugar de MediaBrowserCompat.MediaItem y MediaMetadataCompat. Las partes de tu código vinculadas a las clases heredadas deben cambiarse según corresponda o asignarse alMediaItem
de Media3 en su lugar.El modelo de programación asíncrono general cambió a
Futures
, en contraste con el enfoqueResult
desmontable deMediaBrowserServiceCompat
. La implementación de tu servicio puede mostrar un objetoListenableFuture
asíncrono en lugar de desvincular un resultado o mostrar una interfaz Future inmediata para mostrar directamente un valor.
Quitar PlayerNotificationManager
El MediaLibraryService
admite notificaciones multimedia automáticamente y se puede quitar PlayerNotificationManager
cuando se usa un MediaLibraryService
o MediaSessionService
.
Para personalizar la notificación, la app puede establecer 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.
Cuando se anula MediaLibraryService.updateNotification()
, una app puede asumir la propiedad total de publicar una notificación y de iniciar o detener el servicio en primer plano, según sea necesario.
Cómo migrar el código del cliente con un MediaBrowser
Con AndroidX Media3, un MediaBrowser
implementa las interfaces de MediaController/Player
y se puede usar para controlar la reproducción de contenido multimedia además de explorar la biblioteca multimedia. Si tuvieras que crear un MediaBrowserCompat
y un MediaControllerCompat
en el mundo heredado, puedes hacer lo mismo con solo usar MediaBrowser
en Media3.
Se puede compilar un MediaBrowser
y esperar a que se conecte al servicio que se está estableciendo:
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)
}
Consulta Cómo controlar la reproducción en la sesión multimedia para obtener información sobre cómo crear un objeto MediaController
para controlar la reproducción en segundo plano.
Pasos adicionales y limpieza
Errores de API inestables
Después de migrar a Media3, es posible que veas errores de lint sobre usos inestables de la API.
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
.
Información general
Ni ExoPlayer v1 ni v2 proporcionaron garantías estrictas sobre la compatibilidad binaria de la biblioteca entre versiones posteriores. La superficie 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, en ocasiones, se ingresaban cambios de nombre de símbolos y otros 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 y la baja del símbolo anterior para algunas versiones, a fin de que los desarrolladores tuvieran tiempo 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 a 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 tenía que asegurarse de que ambas dependencias fueran la misma versión; de lo contrario, las incompatibilidades binarias podrí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 aclarar esta distinción, el uso de símbolos de API inestables generan un error de lint, a menos que estén anotados con @OptIn
.
Después de migrar de ExoPlayer v2 a Media3, es posible que veas muchos errores inestables de lint de la API. Esto puede hacer que parezca que Media3 es "menos estable" que ExoPlayer v2. 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 superficie estable de la API de Media3 no están disponibles en ExoPlayer v2. La diferencia radica en que un error de lint ahora te alerta sobre los diferentes niveles de estabilidad.
Cómo controlar errores inestables de lint de API
Consulta la sección de solución de problemas sobre estos errores de lint para obtener información sobre cómo anotar con @OptIn
los usos de Java y Kotlin de las APIs inestables.
APIs obsoletas
Es posible que notes que las llamadas a las APIs obsoletas están tachadas en Android Studio. Te recomendamos reemplazar 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.
![Captura de pantalla: Cómo mostrar JavaDoc con una alternativa al método obsoleto](https://developer.android.com/static/media/media3/exoplayer/images/deprecation.png?authuser=8&hl=es)
Muestras de código y apps de demostración
- App de demostración de la sesión de AndroidX Media3 (para dispositivos móviles y Wear OS)
- Acciones personalizadas
- Notificación de IU del sistema, MediaButton/BT
- Control de reproducción de Asistente de Google
- UAMP: Android Media Player (rama media3) (para dispositivos móviles y 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 y acceso personalizados