Os apps que usam a biblioteca com.google.android.exoplayer2
e androidx.media
autônomas precisam migrar para androidx.media3
. Use
o script de migração para migrar arquivos de build do Gradle, arquivos de origem Java e
Kotlin e arquivos de layout XML do ExoPlayer
2.19.1
para o AndroidX Media3 1.1.1
.
Informações gerais
Antes de migrar, consulte as seções a seguir para saber mais sobre os benefícios das novas APIs, APIs para migrar e os pré-requisitos a que o projeto do seu app precisa atender.
Por que migrar para o Jetpack Media3
- É a nova casa do ExoPlayer, enquanto o
com.google.android.exoplayer2
foi descontinuado. - Acesse a API Player em componentes/processos com
MediaBrowser
/MediaController
. - Use os recursos estendidos da API
MediaSession
eMediaController
. - Divulgue recursos de reprodução com um controle de acesso detalhado.
- Simplifique seu app removendo
MediaSessionConnector
ePlayerNotificationManager
. - Compatível com versões anteriores com APIs de cliente media-compat
(
MediaBrowserCompat
/MediaControllerCompat
/MediaMetadataCompat
)
APIs de mídia para migrar para o AndroidX Media3
- ExoPlayer e as extensões
Isso inclui todos os módulos do projeto ExoPlayer legado, exceto o módulo mediasession que foi descontinuado. Apps ou módulos que dependem de pacotes emcom.google.android.exoplayer2
podem ser migrados com o script de migração. - MediaSessionConnector (dependendo dos
pacotes
androidx.media.*
deandroidx.media:media:1.4.3+
)
Remova oMediaSessionConnector
e use oandroidx.media3.session.MediaSession
. - MediaBrowserServiceCompat (dependendo dos
pacotes
androidx.media.*
deandroidx.media:media:1.4.3+
)
Migre subclasses deandroidx.media.MediaBrowserServiceCompat
paraandroidx.media3.session.MediaLibraryService
e código usandoMediaBrowserCompat.MediaItem
paraandroidx.media3.common.MediaItem
. - MediaBrowserCompat (dependendo dos
pacotes
android.support.v4.media.*
deandroidx.media:media:1.4.3+
)
Migre o código do cliente usandoMediaBrowserCompat
ouMediaControllerCompat
para usar oandroidx.media3.session.MediaBrowser
comandroidx.media3.common.MediaItem
.
Pré-requisitos
Verificar se o projeto está sob controle de origem
Verifique se é possível reverter facilmente as alterações aplicadas por ferramentas de migração com script. Se você ainda não tem seu projeto sob controle de origem, agora é um bom momento para começar. Se, por algum motivo, você não quiser fazer isso, faça uma cópia de backup do seu projeto antes de iniciar a migração.
Atualizar o app
Recomendamos atualizar o projeto para usar a versão mais recente da biblioteca do ExoPlayer e remover todas as chamadas para métodos descontinuados. Se você pretende usar o script para a migração, é necessário associar a versão para a qual está atualizando com a versão processada pelo script.
Aumente a compileSdkVersion do app para 32.
Faça upgrade do Gradle e do Plug-in do Android Studio para Gradle para uma versão recente que funcione com as dependências atualizadas acima. Por exemplo:
- Plug-in do Android para Gradle versão: 7.1.0
- Versão do Gradle: 7.4
Substitua todas as instruções de importação de caracteres curinga que usam um asterisco (*) e use instruções de importação totalmente qualificadas: exclua as instruções de importação de caracteres curinga e use o Android Studio para importar as instruções totalmente qualificadas (F2 - Alt/Enter, F2 - Alt/Enter, ...).
Migre de
com.google.android.exoplayer2.PlayerView
paracom.google.android.exoplayer2.StyledPlayerView
. Isso é necessário porque não há equivalente acom.google.android.exoplayer2.PlayerView
no AndroidX Media3.
Migrar o ExoPlayer com suporte a script
O script facilita a migração de com.google.android.exoplayer2
para a nova
estrutura de pacote e módulo em androidx.media3
. O script aplica
algumas verificações de validação no projeto e imprime avisos se a validação falhar.
Caso contrário, ele aplica os mapeamentos de classes e pacotes renomeados nos
recursos de um projeto Android Gradle escrito em Java ou 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
Como usar o script de migração
Faça o download do script de migração na tag do projeto do ExoPlayer no GitHub correspondente à versão para a qual você atualizou seu app:
curl -o media3-migration.sh \ "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
Torne o script executável:
chmod 744 media3-migration.sh
Execute o script com
--help
para saber mais sobre as opções.Execute o script com
-l
para listar o conjunto de arquivos selecionados para migração. Use-f
para forçar a listagem sem avisos:./media3-migration.sh -l -f /path/to/gradle/project/root
Execute o script com
-m
para mapear pacotes, classes e módulos para a Media3. Executar o script com a opção-m
aplicará as alterações aos arquivos selecionados.- Parar no erro de validação sem fazer mudanças
./media3-migration.sh -m /path/to/gradle/project/root
- Execução forçada
Se o script encontrar uma violação dos pré-requisitos, a migração poderá ser forçada com a sinalização
-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
Conclua estas etapas manuais depois de executar o script com a opção -m
:
- Verifique como o script mudou seu código: use uma ferramenta de diferenças e corrija
possíveis problemas. Registre um bug se você acha que o script tem um
problema geral que foi introduzido sem transmitir a opção
-f
. - Crie o projeto: use
./gradlew clean build
ou, no Android Studio, escolha File > Sync Project with Gradle Files, Build > Clean project e Build > Rebuild project. Monitore seu build na guia "Build - Build Output" do Android Studio.
Etapas de acompanhamento recomendadas:
- Resolva a ativação de erros relacionados ao uso de APIs instáveis.
- Substituir chamadas de API descontinuadas: use a API de substituição sugerida. Mantenha o ponteiro do mouse sobre o aviso no Android Studio e consulte o JavaDoc do símbolo descontinuado para descobrir o que usar em vez de uma determinada chamada.
- Classificar as instruções de importação: abra o projeto no Android Studio, clique com o botão direito do mouse em um nó da pasta de pacotes no visualizador do projeto e escolha Optimize import nos pacotes que contêm os arquivos de origem alterados.
Substitua MediaSessionConnector
por androidx.media3.session.MediaSession
.
No ambiente MediaSessionCompat
legado, o MediaSessionConnector
era
responsável por sincronizar o estado do player com o estado da sessão
e receber comandos de controladores que precisavam de delegação para os métodos
apropriados do jogador. Com o AndroidX Media3, isso é feito pelo MediaSession
diretamente,
sem a necessidade de um conector.
Remover todas as referências e o uso do MediaSessionConnector:se você usou o script automatizado para migrar classes e pacotes do ExoPlayer, o script provavelmente deixou seu código em um estado não compilável em relação ao
MediaSessionConnector
que não pode ser resolvido. O Android Studio mostrará o código corrompido quando você tentar criar ou iniciar o app.No arquivo
build.gradle
em que você mantém as dependências, adicione uma dependência de implementação ao módulo de sessão do AndroidX Media3 e remova a dependência legada:implementation "androidx.media3:media3-session:1.3.1"
Substitua
MediaSessionCompat
porandroidx.media3.session.MediaSession
.No site do código em que você criou o
MediaSessionCompat
legado, useandroidx.media3.session.MediaSession.Builder
para criar umMediaSession
. Transmita o player para construir o criador de sessão.val player = ExoPlayer.Builder(context).build() mediaSession = MediaSession.Builder(context, player) .setSessionCallback(MySessionCallback()) .build()
Implemente
MySessionCallback
conforme exigido pelo app. Isso é opcional. Se você quiser permitir que os controles adicionem itens de mídia ao player, implementeMediaSession.Callback.onAddMediaItems()
. Ele disponibiliza vários métodos de API atuais e legados que adicionam itens de mídia ao player para reprodução de forma compatível com versões anteriores. Isso inclui os métodosMediaController.set/addMediaItems()
do controlador Media3, bem como os métodosTransportControls.prepareFrom*/playFrom*
da API legada. Um exemplo de implementação deonAddMediaItems
pode ser encontrado noPlaybackService
do app de demonstração da sessão.Libere a sessão de mídia no local do código em que você destruiu a sessão antes da migração:
mediaSession?.run { player.release() release() mediaSession = null }
Funcionalidade do MediaSessionConnector
na Media3
A tabela a seguir mostra as APIs Media3 que processam a funcionalidade
implementada anteriormente em MediaSessionConnector
.
MediaSessionConnector | AndroidX Media3 |
---|---|
CustomActionProvider |
MediaSession.Callback.onCustomCommand()/
MediaSession.setCustomLayout() |
PlaybackPreparer |
MediaSession.Callback.onAddMediaItems()
(o prepare() é chamado internamente)
|
QueueNavigator |
ForwardingPlayer |
QueueEditor |
MediaSession.Callback.onAddMediaItems() |
RatingCallback |
MediaSession.Callback.onSetRating() |
PlayerNotificationManager |
DefaultMediaNotificationProvider/
MediaNotification.Provider |
Migrar MediaBrowserService
para MediaLibraryService
O AndroidX Media3 introduz MediaLibraryService
, que substitui o
MediaBrowserServiceCompat
. O JavaDoc de MediaLibraryService
e a superclasse MediaSessionService
dele oferecem uma boa introdução à API e ao modelo de programação assíncrona do serviço.
A MediaLibraryService
é compatível com versões anteriores da
MediaBrowserService
. Um app cliente que está usando MediaBrowserCompat
ou
MediaControllerCompat
continua funcionando sem mudanças de código ao se conectar
a um MediaLibraryService
. Para um cliente, é transparente se o app está
usando um MediaLibraryService
ou um MediaBrowserServiceCompat
legado.
Para que a compatibilidade com versões anteriores funcione, você precisa registrar as duas interfaces de serviço com o serviço na
AndroidManifest.xml
. Dessa forma, um cliente encontra seu serviço pela interface necessária:<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>
No arquivo
build.gradle
em que você mantém as dependências, adicione uma dependência de implementação ao módulo de sessão do AndroidX Media3 e remova a dependência legada:implementation "androidx.media3:media3-session:1.3.1"
Mude seu serviço para herdar de um
MediaLibraryService
em vez deMediaBrowserService
. Como dissemos anteriormente, oMediaLibraryService
é compatível com oMediaBrowserService
legado. Dessa forma, a API mais ampla que o serviço oferece aos clientes ainda é a mesma. Portanto, é provável que um app possa manter a maior parte da lógica necessária para implementar oMediaBrowserService
e adaptá-lo ao novoMediaLibraryService
.As principais diferenças em comparação com o
MediaBrowserServiceCompat
legado são estas:Implemente os métodos do ciclo de vida do serviço:os métodos que precisam ser substituídos no próprio serviço são
onCreate/onDestroy
, em que um app aloca/libera a sessão da biblioteca, o player e outros recursos. Além dos métodos de ciclo de vida de serviço padrão, um app precisa substituironGetSession(MediaSession.ControllerInfo)
para retornar oMediaLibrarySession
que foi criado emonCreate
.Implemente MediaLibraryService.MediaLibrarySessionCallback:criar uma sessão requer uma
MediaLibraryService.MediaLibrarySessionCallback
que implemente os métodos reais da API do domínio. Portanto, em vez de substituir os métodos de API do serviço legado, você modificará os métodos deMediaLibrarySession.Callback
.O callback é usado para criar o
MediaLibrarySession
:mediaLibrarySession = MediaLibrarySession.Builder(this, player, MySessionCallback()) .build()
Encontre a API completa do MediaLibrarySessionCallback na documentação da API.
Implementar
MediaSession.Callback.onAddMediaItems()
: o callbackonAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>)
exibe vários métodos de API atuais e legados que adicionam itens de mídia ao player para reprodução de maneira compatível com versões anteriores. Isso inclui os métodosMediaController.set/addMediaItems()
do controlador Media3, bem como os métodosTransportControls.prepareFrom*/playFrom*
da API legada. Um exemplo de implementação do callback pode ser encontrado noPlaybackService
do app de demonstração da sessão.O AndroidX Media3 está usando
androidx.media3.common.MediaItem
em vez de MediaBrowserCompat.MediaItem e MediaMetadataCompat. Partes do código vinculadas às classes legadas precisam ser alteradas adequadamente ou mapeadas para oMediaItem
do Media3.O modelo de programação assíncrona geral mudou para
Futures
, em oposição à abordagemResult
removível doMediaBrowserServiceCompat
. A implementação do serviço pode retornar umListenableFuture
assíncrono em vez de remover um resultado ou retornar um Future imediato para retornar diretamente um valor.
PlayerNotificationManager foi removido
O MediaLibraryService
oferece suporte a notificações de mídia automaticamente, e o
PlayerNotificationManager
pode ser removido ao usar um MediaLibraryService
ou
MediaSessionService
.
Um app pode personalizar a notificação definindo um MediaNotification.Provider
personalizado em onCreate()
que substitui a
DefaultMediaNotificationProvider
. Em seguida, o MediaLibraryService
inicia o
serviço em primeiro plano, conforme necessário.
Ao substituir MediaLibraryService.updateNotification()
, um app pode assumir
a propriedade total da publicação de uma notificação e da inicialização/interrupção do serviço em
primeiro plano, conforme necessário.
Migrar o código do cliente usando um MediaBrowser
Com o AndroidX Media3, um MediaBrowser
implementa as interfaces de
MediaController/Player
e pode ser usado para controlar a reprodução de mídia, além de navegar pela biblioteca
de mídia. Se você tivesse que criar um MediaBrowserCompat
e um
MediaControllerCompat
no ambiente legado, vai poder fazer o mesmo usando apenas
o MediaBrowser
na Media3.
Um MediaBrowser
pode ser criado e aguardar a conexão com o
serviço que está sendo estabelecida:
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)
}
Consulte
Controlar a reprodução na sessão de mídia
para aprender a criar um MediaController
para controlar a reprodução em
segundo plano.
Outras etapas e limpeza
Erros de API instáveis
Após migrar para o Media3, talvez você veja erros de lint sobre usos instáveis da API.
O uso dessas APIs é seguro, e os erros de lint são derivados das nossas novas
garantias de compatibilidade binária. Se você não precisar de compatibilidade com o binário
estrita, esses erros poderão ser suprimidos com segurança usando uma anotação
@OptIn
.
Contexto
Nem o ExoPlayer v1 nem v2 oferecia garantias rígidas sobre a compatibilidade binária da biblioteca entre as versões subsequentes. A superfície da API do ExoPlayer é muito grande por padrão, permitindo que os apps personalizem quase todos os aspectos da reprodução. As versões subsequentes do ExoPlayer ocasionalmente introduziriam renomeações de símbolos ou outras mudanças interruptivas (por exemplo, novos métodos obrigatórios em interfaces). Na maioria dos casos, essas falhas foram atenuadas com a introdução do novo símbolo e a descontinuação do símbolo antigo em algumas versões, o que permite que os desenvolvedores tenham tempo para migrar os usos, mas isso nem sempre foi possível.
Essas alterações interruptivas resultaram em dois problemas para os usuários das bibliotecas do ExoPlayer v1 e v2:
- Um upgrade para a versão do ExoPlayer pode fazer com que o código pare de ser compilado.
- Um app que dependia do ExoPlayer diretamente e por uma biblioteca intermediária precisava garantir que as duas dependências fossem a mesma versão. Caso contrário, incompatibilidades binárias poderiam resultar em falhas no momento da execução.
Melhorias na Media3
O Media3 garante a compatibilidade binária para um subconjunto da plataforma da API. As
partes que não garantem a compatibilidade binária são marcadas com
@UnstableApi
. Para deixar essa distinção clara, o uso de símbolos de API instáveis
gera um erro de lint, a menos que sejam anotados com @OptIn
.
Após a migração do ExoPlayer v2 para o Media3, você pode encontrar muitos erros de lint de API instáveis. Isso pode fazer parecer que a Media3 é "menos estável" que o ExoPlayer v2. Esse não é o caso. As partes "instáveis" da API Media3 têm o mesmo nível de estabilidade que toda a superfície da API do ExoPlayer v2, e as garantias da superfície estável da API Media3 não estão disponíveis no ExoPlayer v2. A diferença é que um erro de lint agora alerta sobre os diferentes níveis de estabilidade.
Processar erros de lint instável da API
Há duas opções para processar os erros instáveis de lint da API:
- Comece a usar uma API estável que consiga o mesmo resultado.
Continue usando a API instável e anote o uso com
@OptIn
.import androidx.annotation.OptIn import androidx.media3.common.util.UnstableApi @OptIn(UnstableApi::class) fun functionUsingUnstableApi() { // Do something useful. }
Além disso, há uma anotação
kotlin.OptIn
que não pode ser usada. É importante usar a anotaçãoandroidx.annotation.OptIn
para essa finalidade.
Para ativar os pacotes inteiros, adicione um package-info.java
:
@OptIn(markerClass = UnstableApi.class)
package name.of.your.package;
import androidx.annotation.OptIn;
import androidx.media3.common.util.UnstableApi;
Projetos inteiros podem ser ativados suprimindo o erro de lint específico no lint.xml. Consulte o JavaDoc da anotação UnstableApi para mais detalhes.
APIs descontinuadas
As chamadas para APIs descontinuadas são interrompidas no Android Studio. Recomendamos substituir essas chamadas pela alternativa adequada. Passe o cursor sobre o símbolo para ver o JavaDoc que informa qual API usar.
Apps de demonstração e exemplos de código
- App de demonstração da sessão do AndroidX Media3 (dispositivos móveis e WearOS)
- Ações personalizadas
- Notificação da interface do sistema, MediaButton/BT
- Controle de reprodução do Google Assistente
- UAMP: Android Media Player (branch media3) (dispositivo móvel, AutomotiveOS)
- Notificação da interface do sistema, MediaButton/BT, retomada da reprodução
- Controle de reprodução do Google Assistente/WearOS
- AutomotiveOS: comando e login personalizados