Если в вашем приложении используется отдельная библиотека com.google.android.exoplayer2 и androidx.media, перейдите на androidx.media3. Используйте скрипт переноса, чтобы перенести файлы сборки Gradle, исходные файлы Java и Kotlin, а также файлы макета XML из ExoPlayer 2.19.1 в AndroidX Media3 1.1.1.
Обзор
Прежде чем переходить на новые API, ознакомьтесь с разделами ниже. В них рассказывается о преимуществах новых API, о том, какие API нужно перенести, и о требованиях, которым должен соответствовать проект вашего приложения.
Зачем переходить на Jetpack Media3
- Это новый дом для ExoPlayer, а
com.google.android.exoplayer2больше не поддерживается. - Получите доступ к Player API в компонентах и процессах с помощью
MediaBrowser/MediaController. - Используйте расширенные возможности API
MediaSessionиMediaController. - Рекламируйте возможности воспроизведения с помощью детального контроля доступа.
- Упростите приложение, удалив
MediaSessionConnectorиPlayerNotificationManager. - Обратная совместимость с клиентскими API media-compat (
MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat).
Media API, которые нужно перенести в AndroidX Media3
- ExoPlayer и его расширения
Сюда входят все модули устаревшего проекта ExoPlayer, кроме модуля mediasession, поддержка которого прекращена. Приложения или модули, зависящие от пакетов вcom.google.android.exoplayer2, можно перенести с помощью скрипта переноса. - MediaSessionConnector (в зависимости от пакетов
androidx.media.*вandroidx.media:media:1.4.3+)
УдалитеMediaSessionConnectorи используйтеandroidx.media3.session.MediaSession. - MediaBrowserServiceCompat (в зависимости от пакетов
androidx.media.*вandroidx.media:media:1.4.3+)
Перенесите подклассыandroidx.media.MediaBrowserServiceCompatвandroidx.media3.session.MediaLibraryServiceи код, использующийMediaBrowserCompat.MediaItem, вandroidx.media3.common.MediaItem. - MediaBrowserCompat (в зависимости от пакетов
android.support.v4.media.*androidx.media:media:1.4.3+)
Перенесите код клиента, использующийMediaBrowserCompatилиMediaControllerCompat, чтобы использоватьandroidx.media3.session.MediaBrowserсandroidx.media3.common.MediaItem.
Требования
Убедитесь, что ваш проект находится под управлением системы контроля версий
Убедитесь, что вы можете отменить изменения, внесенные инструментами переноса на основе скриптов. Если вы ещё не используете систему контроля версий, самое время начать. Если по какой-то причине вы не хотите этого делать, создайте резервную копию проекта перед началом переноса.
Как обновить приложение
Рекомендуем обновить проект, чтобы использовать последнюю версию библиотеки ExoPlayer, и удалить все вызовы устаревших методов. Если вы планируете использовать скрипт для переноса, вам нужно сопоставить версию, на которую вы обновляетесь, с версией, обрабатываемой скриптом.
Увеличьте значение compileSdkVersion в приложении как минимум до 32.
Обновите Gradle и плагин Android Studio Gradle до последней версии, которая работает с обновленными зависимостями, упомянутыми выше. Пример:
- Версия плагина Android Gradle: 7.1.0.
- Версия Gradle: 7.4.
Замените все операторы импорта с подстановочными знаками, в которых используется звездочка (*), на полные операторы импорта. Для этого удалите операторы импорта с подстановочными знаками и импортируйте полные операторы с помощью Android Studio (F2 – Alt/Enter, F2 – Alt/Enter и т. д.).
Перенесите данные из
com.google.android.exoplayer2.PlayerViewвcom.google.android.exoplayer2.StyledPlayerView. Это необходимо, потому что в AndroidX Media3 нет эквивалентаcom.google.android.exoplayer2.PlayerView.
Переход на ExoPlayer с помощью скрипта
Скрипт упрощает переход с com.google.android.exoplayer2 на новую структуру пакетов и модулей в androidx.media3. Скрипт выполняет несколько проверок вашего проекта и выводит предупреждения, если они не пройдены.
В противном случае он применяет сопоставления переименованных классов и пакетов в ресурсах проекта Android Gradle, написанного на Java или 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
Как использовать скрипт переноса
Скачайте скрипт переноса из тега проекта ExoPlayer на GitHub, соответствующего версии, до которой вы обновили приложение.
curl -o media3-migration.sh \ "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"Сделайте скрипт исполняемым:
chmod 744 media3-migration.shЧтобы узнать о доступных параметрах, запустите скрипт с флагом
--help.Запустите скрипт с параметром
-l, чтобы получить список файлов, выбранных для переноса. Чтобы получить список без предупреждений, используйте параметр-f../media3-migration.sh -l -f /path/to/gradle/project/rootЗапустите скрипт с
-m, чтобы сопоставить пакеты, классы и модули с Media3. Если запустить скрипт с параметром-m, изменения будут применены к выбранным файлам.- Остановить при ошибке проверки без внесения изменений
./media3-migration.sh -m /path/to/gradle/project/root- Принудительное выполнение
Если скрипт обнаружит нарушение предварительных требований, перенос можно выполнить принудительно с помощью флага
-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
После запуска скрипта с параметром -m выполните следующие действия вручную:
- Проверьте, как скрипт изменил ваш код. Используйте инструмент diff и исправьте потенциальные проблемы. Если вы считаете, что скрипт имеет общую проблему, которая была введена без передачи параметра
-f, сообщите об ошибке. - Скомпилируйте проект. Используйте
./gradlew clean buildили в Android Studio выберите File (Файл) > Sync Project with Gradle Files (Синхронизировать проект с файлами Gradle), затем Build (Сборка) > Clean project (Очистить проект) и Build (Сборка) > Rebuild project (Пересобрать проект). Следить за процессом можно на вкладке Build – Build Output (Сборка – Выходные данные сборки) в Android Studio.
Рекомендуемые дальнейшие действия:
- Устраните ошибки, связанные с использованием нестабильных API.
- Замените вызовы устаревших API. Используйте рекомендуемый API. Наведите указатель на предупреждение в Android Studio и посмотрите в JavaDoc устаревшего символа, что нужно использовать вместо него.
- Отсортируйте операторы импорта. Откройте проект в Android Studio, нажмите правой кнопкой мыши на узел папки пакета в окне просмотра проекта и выберите Optimize imports (Оптимизировать импорт) для пакетов, содержащих измененные исходные файлы.
Замените MediaSessionConnector на androidx.media3.session.MediaSession
В устаревшей версии MediaSessionCompat класс MediaSessionConnector отвечал за синхронизацию состояния проигрывателя с состоянием сеанса и получение команд от контроллеров, которые нужно было делегировать соответствующим методам проигрывателя. В AndroidX Media3 это делается напрямую с помощью MediaSession без коннектора.
Удалите все ссылки на MediaSessionConnector и его использование. Если вы использовали автоматизированный скрипт для переноса классов и пакетов ExoPlayer, то, скорее всего, скрипт оставил ваш код в некомпилируемом состоянии из-за
MediaSessionConnector, который невозможно разрешить. Android Studio покажет вам неработающий код, когда вы попытаетесь собрать или запустить приложение.В файле
build.gradle, где вы управляете зависимостями, добавьте зависимость реализации к модулю сеанса AndroidX Media3 и удалите устаревшую зависимость:implementation "androidx.media3:media3-session:1.11.1"Замените
MediaSessionCompatнаandroidx.media3.session.MediaSession.На сайте, где вы создали устаревший
MediaSessionCompat, используйтеandroidx.media3.session.MediaSession.Builder, чтобы создатьMediaSession. Передайте проигрыватель, чтобы создать конструктор сеансов.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();
При необходимости реализуйте
MySessionCallback. Это необязательно. Если вы хотите разрешить контроллерам добавлять мультимедийные объекты в проигрыватель, реализуйтеMediaSession.Callback.onAddMediaItems(). Он поддерживает различные текущие и устаревшие методы API, которые добавляют мультимедийные объекты в проигрыватель для воспроизведения с обратной совместимостью. Это относится к методамMediaController.set/addMediaItems()контроллера Media3 и методамTransportControls.prepareFrom*/playFrom*устаревшего API. Пример реализацииonAddMediaItemsможно найти вPlaybackServiceдемонстрационного приложения.Освободите сеанс воспроизведения в том месте кода, где вы удалили сеанс до переноса:
Kotlin
mediaSession?.run { player.release() release() mediaSession = null }
Java
if (mediaSession != null) { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; }
Функции MediaSessionConnector в Media3
В таблице ниже показано, какие API Media3 обрабатывают функции, ранее реализованные в MediaSessionConnector.
| MediaSessionConnector | AndroidX Media3 |
|---|---|
CustomActionProvider |
MediaSession.Callback.onCustomCommand()/
MediaSession.setMediaButtonPreferences() |
PlaybackPreparer |
MediaSession.Callback.onAddMediaItems()
(prepare() вызывается внутри)
|
QueueNavigator |
ForwardingSimpleBasePlayer |
QueueEditor |
MediaSession.Callback.onAddMediaItems() |
RatingCallback |
MediaSession.Callback.onSetRating() |
PlayerNotificationManager |
DefaultMediaNotificationProvider/
MediaNotification.Provider |
Перенести MediaBrowserService в MediaLibraryService
В AndroidX Media3 появился класс MediaLibraryService, который заменяет MediaBrowserServiceCompat. Документация JavaDoc для MediaLibraryService и его суперкласса MediaSessionService содержит хорошее введение в API и модель асинхронного программирования сервиса.
MediaLibraryService обратно совместим с MediaBrowserService. Клиентское приложение, использующее MediaBrowserCompat или MediaControllerCompat, продолжает работать без изменений кода при подключении к MediaLibraryService. Для клиента не имеет значения, использует ли ваше приложение MediaLibraryService или устаревший MediaBrowserServiceCompat.
Чтобы обеспечить обратную совместимость, необходимо зарегистрировать оба интерфейса сервиса в файле
AndroidManifest.xml. Таким образом, клиент находит ваш сервис по требуемому интерфейсу сервиса:<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>В файле
build.gradle, где вы управляете зависимостями, добавьте зависимость реализации к модулю сеанса AndroidX Media3 и удалите устаревшую зависимость:implementation "androidx.media3:media3-session:1.11.1"Измените сервис, чтобы он наследовал от
MediaLibraryService, а не отMediaBrowserService. Как уже говорилось,MediaLibraryServiceсовместим с устаревшимMediaBrowserService. Соответственно, более широкий API, который сервис предлагает клиентам, остался прежним. Поэтому, скорее всего, в приложении можно сохранить большую часть логики, необходимой для реализацииMediaBrowserService, и адаптировать ее для новогоMediaLibraryService.Основные отличия от устаревшего метода
MediaBrowserServiceCompat:Реализуйте методы жизненного цикла сервиса. В самом сервисе необходимо переопределить методы
onCreateиonDestroy, в которых приложение выделяет или освобождает сеанс библиотеки, проигрыватель и другие ресурсы. Помимо стандартных методов жизненного цикла сервиса, приложение должно переопределитьonGetSession(MediaSession.ControllerInfo), чтобы возвращатьMediaLibrarySession, созданный вonCreate.Реализуйте MediaLibraryService.MediaLibrarySessionCallback. Чтобы создать сеанс, требуется
MediaLibraryService.MediaLibrarySessionCallback, который реализует методы API домена. Поэтому вместо переопределения методов API устаревшего сервиса вы будете переопределять методыMediaLibrarySession.Callback.Затем обратный вызов используется для создания
MediaLibrarySession:Kotlin
mediaLibrarySession = MediaLibrarySession.Builder(context, player, MySessionCallback()).build()
Java
mediaLibrarySession = new MediaLibrarySession.Builder(context, player, new MySessionCallback()).build();
Полный API MediaLibrarySessionCallback можно найти в документации по API.
Реализуйте
MediaSession.Callback.onAddMediaItems().onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>)Обратный вызов обслуживает различные текущие и устаревшие методы API, которые добавляют мультимедийные объекты в проигрыватель для воспроизведения с обратной совместимостью. Это касается методовMediaController.set/addMediaItems()контроллера Media3, а также методовTransportControls.prepareFrom*/playFrom*устаревшего API. Пример реализации обратного вызова можно найти вPlaybackServiceдемонстрационного приложения.В AndroidX Media3 вместо
MediaBrowserCompat.MediaItemиMediaMetadataCompatиспользуетсяandroidx.media3.common.MediaItem. Части кода, связанные с устаревшими классами, необходимо соответствующим образом изменить или сопоставить сMediaItemMedia3.Общая модель асинхронного программирования изменена на
Futuresв отличие от отсоединяемого подходаResultвMediaBrowserServiceCompat. Реализация сервиса может возвращать асинхронный объектListenableFutureвместо отсоединения результата или возвращать немедленный объект Future, чтобы напрямую возвращать значение.
Удаление PlayerNotificationManager
MediaLibraryService автоматически поддерживает уведомления мультимедиа, а PlayerNotificationManager можно удалить при использовании MediaLibraryService или MediaSessionService.
Приложение может настроить уведомление, задав собственное значение MediaNotification.Provider в onCreate(), которое заменит DefaultMediaNotificationProvider. Затем MediaLibraryService запускает службу в активном режиме.
Переопределив MediaLibraryService.updateNotification(), приложение может полностью взять на себя ответственность за публикацию уведомления и запуск или остановку службы в активном режиме по мере необходимости.
Перенос кода клиента с помощью MediaBrowser
В AndroidX Media3 MediaBrowser реализует интерфейсы MediaController/Player и может использоваться для управления воспроизведением медиаконтента, а также для просмотра медиатеки. Если в устаревшей версии вам приходилось создавать MediaBrowserCompat и MediaControllerCompat, то в Media3 достаточно использовать только MediaBrowser.
MediaBrowser можно создать и дождаться подключения к сервису:
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();
Чтобы узнать, как создать MediaController для управления воспроизведением в фоновом режиме, прочитайте статью Управление воспроизведением в сеансе мультимедиа.
Дальнейшие действия и удаление
В следующих разделах объясняется, как обрабатывать ошибки линтинга нестабильных API и устаревшие API после завершения первоначальной миграции.
Ошибки нестабильного API
После перехода на Media3 вы можете увидеть ошибки lint, связанные с использованием нестабильных API.
Эти API безопасны для использования, а ошибки линтинга – побочный продукт нашей новой политики бинарной совместимости. Если вам не требуется строгая двоичная совместимость, эти ошибки можно безопасно подавить с помощью аннотации @OptIn.
Фон
Ни ExoPlayer v1, ни ExoPlayer v2 не обеспечивали строгую двоичную совместимость библиотеки между последующими версиями. API ExoPlayer имеет очень большую поверхность, чтобы приложения могли настраивать практически каждый аспект воспроизведения. В последующих версиях ExoPlayer иногда переименовывались символы или вносились другие критические изменения (например, добавлялись новые обязательные методы в интерфейсы). В большинстве случаев эти сбои устранялись путем введения нового символа наряду с устареванием старого символа для нескольких версий, чтобы дать разработчикам время перенести их использование, но это не всегда было возможно.
Эти критические изменения привели к двум проблемам для пользователей библиотек ExoPlayer версий 1 и 2:
- Обновление версии ExoPlayer может привести к тому, что код перестанет компилироваться.
- Если приложение зависело от ExoPlayer как напрямую, так и через промежуточную библиотеку, нужно было убедиться, что обе зависимости имеют одну и ту же версию. В противном случае несовместимость двоичных файлов могла привести к сбоям во время выполнения.
Улучшения в Media3
Media3 обеспечивает двоичную совместимость для подмножества поверхности API. Части, которые не обеспечивают двоичную совместимость, помечены как @UnstableApi.
Чтобы сделать это различие очевидным, использование нестабильных символов API генерирует ошибку lint, если они не аннотированы с помощью @OptIn.
После перехода с ExoPlayer версии 2 на Media3 вы можете увидеть много ошибок линтинга нестабильного API. Из-за этого может показаться, что Media3 менее стабильна, чем ExoPlayer версии 2. На самом деле это не так: Нестабильные части Media3 API имеют тот же уровень стабильности, что и весь API ExoPlayer версии 2, а двоичная совместимость стабильного Media3 API в ExoPlayer версии 2 вообще недоступна. Разница в том, что теперь ошибка линтинга предупреждает вас о разных уровнях стабильности.
Как устранять ошибки линтинга нестабильного API
Подробные сведения о том, как аннотировать использование нестабильных API в Java и Kotlin с помощью @OptIn, можно найти в разделе об устранении неполадок, связанных с этими ошибками.
Устаревшие API
Вызовы устаревших API в Android Studio могут быть зачеркнуты. Рекомендуем заменить такие вызовы подходящей альтернативой. Наведите указатель мыши на символ, чтобы увидеть JavaDoc, в котором указано, какой API использовать вместо этого.
Примеры кода и демоприложения
- Демонстрационное приложение AndroidX Media3 session (для мобильных устройств и Wear OS)
- Специальные действия
- Уведомление системного интерфейса, MediaButton/BT
- Управление воспроизведением с помощью Google Ассистента
- UAMP: Android Media Player (ветка media3) (мобильные устройства, AutomotiveOS)
- Уведомление системного интерфейса, MediaButton/BT, возобновление воспроизведения
- Управление воспроизведением с помощью Google Ассистента или Wear OS
- AutomotiveOS: пользовательская команда и вход