Guide de migration AndroidX Media3

Les applications qui utilisent actuellement la bibliothèque com.google.android.exoplayer2 autonome et androidx.media doivent migrer vers androidx.media3. Utilisez le script de migration pour migrer les fichiers de compilation Gradle, les fichiers sources Java et Kotlin, et les fichiers de mise en page XML d'ExoPlayer 2.19.1 vers AndroidX Media3 1.1.1.

Présentation

Avant de procéder à la migration, consultez les sections suivantes pour en savoir plus sur les avantages des nouvelles API, les API à migrer et les conditions préalables que le projet de votre application doit remplir.

Pourquoi migrer vers Jetpack Media3 ?

  • Il s'agit du nouvel espace dédié à ExoPlayer, tandis que com.google.android.exoplayer2 est abandonné.
  • Accédez à l'API Player sur l'ensemble des composants/processus avec MediaBrowser/MediaController.
  • Utilisez les fonctionnalités étendues de l'API MediaSession et MediaController.
  • Annoncez les fonctionnalités de lecture avec un contrôle des accès ultraprécis.
  • Simplifiez votre application en supprimant MediaSessionConnector et PlayerNotificationManager.
  • Rétrocompatible avec les API clientes media-compat (MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat)

API multimédias à migrer vers AndroidX Media3

  • ExoPlayer et ses extensions
    Cela inclut tous les modules de l'ancien projet ExoPlayer, à l'exception du module mediasession, qui n'est plus disponible. Les applications ou modules dépendant de packages dans com.google.android.exoplayer2 peuvent être migrés à l'aide du script de migration.
  • MediaSessionConnector (en fonction des packages androidx.media.* de androidx.media:media:1.4.3+)
    Supprimez MediaSessionConnector et utilisez androidx.media3.session.MediaSession à la place.
  • MediaBrowserServiceCompat (en fonction des packages androidx.media.* de androidx.media:media:1.4.3+)
    Migrez les sous-classes de androidx.media.MediaBrowserServiceCompat vers androidx.media3.session.MediaLibraryService et le code utilisant MediaBrowserCompat.MediaItem vers androidx.media3.common.MediaItem.
  • MediaBrowserCompat (en fonction des packages android.support.v4.media.* de androidx.media:media:1.4.3+)
    Migrez le code client à l'aide de MediaBrowserCompat ou MediaControllerCompat pour utiliser androidx.media3.session.MediaBrowser avec androidx.media3.common.MediaItem.

Prérequis

  1. Assurez-vous que votre projet est sous contrôle de code source

    Assurez-vous de pouvoir facilement annuler les modifications appliquées par les outils de migration par script. Si vous n'avez pas encore placé votre projet sous contrôle de code source, c'est le moment de le faire. Si, pour une raison quelconque, vous ne souhaitez pas le faire, effectuez une copie de sauvegarde de votre projet avant de commencer la migration.

  2. Mettre à jour votre application

    • Nous vous recommandons de mettre à jour votre projet pour utiliser la version la plus récente de la bibliothèque ExoPlayer et de supprimer tous les appels aux méthodes obsolètes. Si vous prévoyez d'utiliser le script pour la migration, vous devez faire correspondre la version vers laquelle vous effectuez la mise à jour avec la version gérée par le script.

    • Augmentez la valeur compileSdkVersion de votre application pour qu'elle soit d'au moins 32.

    • Mettez à niveau Gradle et le plug-in Gradle d'Android Studio vers une version récente compatible avec les dépendances mises à jour ci-dessus. Par exemple :

      • Version du plug-in Android Gradle : 7.1.0
      • Version de Gradle : 7.4
    • Remplacez toutes les instructions d'importation avec caractère générique qui utilisent un astérisque (*) par des instructions d'importation complètes : supprimez les instructions d'importation avec caractère générique et utilisez Android Studio pour importer les instructions complètes (F2 - Alt/Entrée, F2 - Alt/Entrée, etc.).

    • Migrer de com.google.android.exoplayer2.PlayerView vers com.google.android.exoplayer2.StyledPlayerView. Cette étape est nécessaire, car il n'existe pas d'équivalent à com.google.android.exoplayer2.PlayerView dans AndroidX Media3.

Migrer ExoPlayer avec la compatibilité des scripts

Le script facilite le passage de com.google.android.exoplayer2 à la nouvelle structure de package et de module sous androidx.media3. Le script applique des vérifications de validation à votre projet et affiche des avertissements en cas d'échec de la validation. Sinon, il applique les mappages des classes et des packages renommés dans les ressources d'un projet Gradle Android écrit en Java ou en 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

Utiliser le script de migration

  1. Téléchargez le script de migration à partir du tag du projet ExoPlayer sur GitHub correspondant à la version vers laquelle vous avez mis à jour votre application :

    curl -o media3-migration.sh \
      "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
    
  2. Rendez le script exécutable :

    chmod 744 media3-migration.sh
    
  3. Exécutez le script avec --help pour en savoir plus sur les options.

  4. Exécutez le script avec -l pour lister l'ensemble des fichiers sélectionnés pour la migration (utilisez -f pour forcer l'affichage de la liste sans avertissement) :

    ./media3-migration.sh -l -f /path/to/gradle/project/root
    
  5. Exécutez le script avec -m pour mapper les packages, les classes et les modules vers Media3. L'exécution du script avec l'option -m applique les modifications aux fichiers sélectionnés.

    • Arrêter en cas d'erreur de validation sans apporter de modifications
    ./media3-migration.sh -m /path/to/gradle/project/root
    
    • Exécution forcée

    Si le script détecte un non-respect des conditions préalables, la migration peut être forcée avec l'option -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

Effectuez ces étapes manuelles après avoir exécuté le script avec l'option -m :

  1. Vérifiez comment le script a modifié votre code : utilisez un outil de comparaison et corrigez les problèmes potentiels (envisagez de signaler un bug si vous pensez que le script présente un problème général qui a été introduit sans transmettre l'option -f).
  2. Créer le projet : utilisez ./gradlew clean build ou, dans Android Studio, sélectionnez File > Sync Project with Gradle Files (Fichier > Synchroniser le projet avec les fichiers Gradle), puis Build > Clean project (Compiler > Nettoyer le projet) et Build > Rebuild project (Compiler > Recompiler le projet). Surveillez votre compilation dans l'onglet "Build - Build Output" (Compilation - Sortie de compilation) d'Android Studio.

Procédure à suivre recommandée :

  1. Résolvez l'activation des erreurs concernant l'utilisation d'API instables.
  2. Remplacer les appels d'API obsolètes : utilisez l'API de remplacement suggérée. Passez le pointeur sur l'avertissement dans Android Studio et consultez la JavaDoc du symbole obsolète pour savoir quoi utiliser à la place d'un appel donné.
  3. Trier les instructions d'importation : ouvrez le projet dans Android Studio, puis effectuez un clic droit sur un nœud de dossier de package dans l'outil de visualisation de projet et sélectionnez Optimize imports (Optimiser les importations) sur les packages contenant les fichiers sources modifiés.

Remplacer MediaSessionConnector par androidx.media3.session.MediaSession

Dans l'ancien monde MediaSessionCompat, MediaSessionConnector était chargé de synchroniser l'état du lecteur avec l'état de la session et de recevoir des commandes des contrôleurs qui devaient être déléguées aux méthodes de lecteur appropriées. Avec AndroidX Media3, cette opération est effectuée directement par MediaSession, sans connecteur.

  1. Supprimez toutes les références et l'utilisation de MediaSessionConnector : si vous avez utilisé le script automatisé pour migrer les classes et les packages ExoPlayer, il est probable que le script ait laissé votre code dans un état non compilable concernant le MediaSessionConnector qui ne peut pas être résolu. Android Studio vous montrera le code défectueux lorsque vous tenterez de compiler ou de démarrer l'application.

  2. Dans le fichier build.gradle où vous gérez vos dépendances, ajoutez une dépendance d'implémentation au module de session AndroidX Media3 et supprimez l'ancienne dépendance :

    implementation "androidx.media3:media3-session:1.11.1"
    
  3. Remplacez MediaSessionCompat par androidx.media3.session.MediaSession.

  4. Sur le site de code où vous avez créé l'ancien MediaSessionCompat, utilisez androidx.media3.session.MediaSession.Builder pour compiler un MediaSession. Transmettez le lecteur pour construire le compilateur de session.

    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();

  5. Implémentez MySessionCallback selon les besoins de votre application. Cette étape est facultative. Si vous souhaitez autoriser les contrôleurs à ajouter des éléments multimédias au lecteur, implémentez MediaSession.Callback.onAddMediaItems(). Elle diffuse diverses méthodes d'API actuelles et anciennes qui ajoutent des éléments multimédias au lecteur pour la lecture de manière rétrocompatible. Cela inclut les méthodes MediaController.set/addMediaItems() du contrôleur Media3, ainsi que les méthodes TransportControls.prepareFrom*/playFrom* de l'ancienne API. Vous trouverez un exemple d'implémentation de onAddMediaItems dans le PlaybackService de l'application de démonstration de session.

  6. Libérez la session multimédia au niveau de l'emplacement du code où vous avez détruit votre session avant la migration :

    Kotlin

    mediaSession?.run {
      player.release()
      release()
      mediaSession = null
    }

    Java

    if (mediaSession != null) {
      mediaSession.getPlayer().release();
      mediaSession.release();
      mediaSession = null;
    }

Fonctionnalité MediaSessionConnector dans Media3

Le tableau suivant présente les API Media3 qui gèrent les fonctionnalités précédemment implémentées dans MediaSessionConnector.

MediaSessionConnectorAndroidX Media3
CustomActionProvider MediaSession.Callback.onCustomCommand()/ MediaSession.setMediaButtonPreferences()
PlaybackPreparer MediaSession.Callback.onAddMediaItems() (prepare() est appelé en interne)
QueueNavigator ForwardingSimpleBasePlayer
QueueEditor MediaSession.Callback.onAddMediaItems()
RatingCallback MediaSession.Callback.onSetRating()
PlayerNotificationManager DefaultMediaNotificationProvider/ MediaNotification.Provider

Migrer MediaBrowserService vers MediaLibraryService

AndroidX Media3 introduit MediaLibraryService, qui remplace MediaBrowserServiceCompat. La documentation JavaDoc de MediaLibraryService et de sa superclasse MediaSessionService fournit une bonne introduction à l'API et au modèle de programmation asynchrone du service.

MediaLibraryService est rétrocompatible avec MediaBrowserService. Une application cliente qui utilise MediaBrowserCompat ou MediaControllerCompat continue de fonctionner sans modification du code lors de la connexion à un MediaLibraryService. Pour un client, l'utilisation d'un MediaLibraryService ou d'un MediaBrowserServiceCompat hérité par votre application est transparente.

Schéma des composants d'une application avec un service, une activité et des applications externes.
Figure 1 : Présentation des composants d'une application multimédia
  1. Pour que la rétrocompatibilité fonctionne, vous devez enregistrer les deux interfaces de service auprès de votre service dans le AndroidManifest.xml. De cette façon, un client trouve votre service via l'interface de service requise :

    <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. Dans le fichier build.gradle où vous gérez vos dépendances, ajoutez une dépendance d'implémentation au module de session AndroidX Media3 et supprimez l'ancienne dépendance :

    implementation "androidx.media3:media3-session:1.11.1"
    
  3. Modifiez votre service pour qu'il hérite d'un MediaLibraryService au lieu de MediaBrowserService. Comme indiqué précédemment, MediaLibraryService est compatible avec l'ancien MediaBrowserService. Par conséquent, l'API plus large que le service propose aux clients reste la même. Il est donc probable qu'une application puisse conserver la majeure partie de la logique requise pour implémenter MediaBrowserService et l'adapter au nouveau MediaLibraryService.

    Voici les principales différences par rapport à l'ancien MediaBrowserServiceCompat :

    • Implémenter les méthodes de cycle de vie du service : les méthodes à remplacer sur le service lui-même sont onCreate/onDestroy, où une application alloue/libère la session de bibliothèque, le lecteur et d'autres ressources. En plus des méthodes standards du cycle de vie du service, une application doit remplacer onGetSession(MediaSession.ControllerInfo) pour renvoyer le MediaLibrarySession créé dans onCreate.

    • Implémenter MediaLibraryService.MediaLibrarySessionCallback : la création d'une session nécessite un MediaLibraryService.MediaLibrarySessionCallback qui implémente les méthodes d'API de domaine réelles. Ainsi, au lieu de remplacer les méthodes d'API de l'ancien service, vous remplacerez celles de MediaLibrarySession.Callback.

      Le rappel est ensuite utilisé pour créer le MediaLibrarySession :

      Kotlin

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

      Java

      mediaLibrarySession =
          new MediaLibrarySession.Builder(context, player, new MySessionCallback()).build();

      Consultez l'API complète de MediaLibrarySessionCallback dans la documentation de l'API.

    • Implémentez MediaSession.Callback.onAddMediaItems() : le rappel onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) diffuse diverses méthodes d'API actuelles et anciennes qui ajoutent des éléments multimédias au lecteur pour la lecture de manière rétrocompatible. Cela inclut les méthodes MediaController.set/addMediaItems() du contrôleur Media3, ainsi que les méthodes TransportControls.prepareFrom*/playFrom* de l'ancienne API. Vous trouverez un exemple d'implémentation du rappel dans le PlaybackService de l'application de démonstration de session.

    • AndroidX Media3 utilise androidx.media3.common.MediaItem au lieu de MediaBrowserCompat.MediaItem et MediaMetadataCompat. Les parties de votre code liées aux anciennes classes doivent être modifiées en conséquence ou mappées à la classe MediaItem de Media3.

    • Le modèle de programmation asynchrone général est passé à Futures, contrairement à l'approche Result dissociable de MediaBrowserServiceCompat. Votre implémentation de service peut renvoyer un ListenableFuture asynchrone au lieu de dissocier un résultat ou renvoyer un Future immédiat pour renvoyer directement une valeur.

Supprimer PlayerNotificationManager

MediaLibraryService accepte automatiquement les notifications multimédias, et PlayerNotificationManager peut être supprimé lorsque vous utilisez MediaLibraryService ou MediaSessionService.

Une application peut personnaliser la notification en définissant un MediaNotification.Provider personnalisé dans onCreate() qui remplace DefaultMediaNotificationProvider. MediaLibraryService se charge ensuite de démarrer le service au premier plan, si nécessaire.

En remplaçant MediaLibraryService.updateNotification(), une application peut s'approprier pleinement la publication d'une notification et le démarrage/l'arrêt du service au premier plan, si nécessaire.

Migrer le code client à l'aide d'un MediaBrowser

Avec AndroidX Media3, un MediaBrowser implémente les interfaces MediaController/Player et peut être utilisé pour contrôler la lecture de contenus multimédias, en plus de parcourir la bibliothèque multimédia. Si vous deviez créer un MediaBrowserCompat et un MediaControllerCompat dans l'ancien monde, vous pouvez faire de même en utilisant uniquement le MediaBrowser dans Media3.

Un MediaBrowser peut être créé et attendre que la connexion au service soit établie :

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();

Consultez Contrôler la lecture dans la session multimédia pour découvrir comment créer un MediaController afin de contrôler la lecture en arrière-plan.

Étapes suivantes et nettoyage

Erreurs d'API instables

Après la migration vers Media3, vous pouvez voir des erreurs lint concernant des utilisations d'API instables. Ces API peuvent être utilisées en toute sécurité, et les erreurs lint sont un sous-produit de nos nouvelles garanties de compatibilité binaire. Si vous n'avez pas besoin d'une compatibilité binaire stricte, vous pouvez supprimer ces erreurs en toute sécurité à l'aide d'une annotation @OptIn.

Arrière-plan

Ni ExoPlayer v1 ni ExoPlayer v2 ne fournissaient de garanties strictes concernant la compatibilité binaire de la bibliothèque entre les versions ultérieures. La surface de l'API ExoPlayer est très vaste, ce qui permet aux applications de personnaliser presque tous les aspects de la lecture. Les versions ultérieures d'ExoPlayer introduisaient parfois des renommages de symboles ou d'autres modifications destructives (par exemple, de nouvelles méthodes requises sur les interfaces). Dans la plupart des cas, ces problèmes ont été atténués en introduisant le nouveau symbole tout en abandonnant l'ancien symbole pendant quelques versions, afin de laisser aux développeurs le temps de migrer leurs utilisations, mais cela n'a pas toujours été possible.

Ces modifications destructives ont entraîné deux problèmes pour les utilisateurs des bibliothèques ExoPlayer v1 et v2 :

  1. La mise à niveau vers la version ExoPlayer peut entraîner l'arrêt de la compilation du code.
  2. Une application qui dépendait d'ExoPlayer à la fois directement et via une bibliothèque intermédiaire devait s'assurer que les deux dépendances étaient de la même version. Sinon, des incompatibilités binaires pouvaient entraîner des plantages au moment de l'exécution.

Améliorations apportées à Media3

Media3 garantit la compatibilité binaire pour un sous-ensemble de la surface de l'API. Les parties qui ne garantissent pas la compatibilité binaire sont marquées par @UnstableApi. Pour que cette distinction soit claire, l'utilisation de symboles d'API instables génère une erreur lint, sauf s'ils sont annotés avec @OptIn.

Après avoir migré d'ExoPlayer v2 vers Media3, vous risquez de voir de nombreuses erreurs lint d'API instables. Cela peut donner l'impression que Media3 est "moins stable" qu'ExoPlayer v2. Ce n'est pas le cas. Les parties "instables" de l'API Media3 ont le même niveau de stabilité que l'ensemble de la surface de l'API ExoPlayer v2, et les garanties de la surface de l'API Media3 stable ne sont pas du tout disponibles dans ExoPlayer v2. La différence est simplement qu'une erreur lint vous avertit désormais des différents niveaux de stabilité.

Gérer les erreurs de lint d'API instables

Consultez la section de dépannage sur ces erreurs lint pour savoir comment annoter les utilisations Java et Kotlin d'API instables avec @OptIn.

API obsolètes

Vous remarquerez peut-être que les appels aux API obsolètes sont barrés dans Android Studio. Nous vous recommandons de remplacer ces appels par l'alternative appropriée. Pointez sur le symbole pour afficher la JavaDoc qui indique l'API à utiliser à la place.

Capture d'écran : comment afficher JavaDoc avec une alternative à la méthode obsolète
Figure 3 : L'info-bulle JavaDoc dans Android Studio suggère une alternative pour tout symbole obsolète.

Exemples de code et applications de démonstration