当前正在使用独立 com.google.android.exoplayer2
库和 androidx.media
的应用应迁移到 androidx.media3
。使用 迁移脚本 将 Gradle 构建文件、Java 和 Kotlin 源文件以及 XML 布局文件从 ExoPlayer 2.19.1
迁移到 AndroidX Media3 1.1.1
。
概述
在迁移之前,请查看以下部分,了解新 API 的优势、需要迁移的 API 以及应用项目应满足的先决条件。
为什么要迁移到 Jetpack Media3
- 它是 **ExoPlayer 的新家**,而
com.google.android.exoplayer2
已停止使用。 - 使用
MediaBrowser
/MediaController
在组件/进程之间访问 **播放器 API**。 - 使用 **
MediaSession
和MediaController
的扩展功能** API。 - 通过 **细粒度的访问控制** 公告播放功能。
- 通过移除
MediaSessionConnector
和PlayerNotificationManager
**简化您的应用**。 - 与媒体兼容客户端 API(
MediaBrowserCompat
/MediaControllerCompat
/MediaMetadataCompat
)**向后兼容**
需要迁移到 AndroidX Media3 的媒体 API
- ExoPlayer 及其扩展
这包括旧版 ExoPlayer 项目 的所有模块,除了已停止使用的 mediasession 模块。依赖于com.google.android.exoplayer2
中包的应用或模块可以使用迁移脚本进行迁移。 - MediaSessionConnector(依赖于
androidx.media:media:1.4.3+
的androidx.media.*
包)
移除MediaSessionConnector
并改用androidx.media3.session.MediaSession
。 - MediaBrowserServiceCompat(依赖于
androidx.media:media:1.4.3+
的androidx.media.*
包)
将androidx.media.MediaBrowserServiceCompat
的子类迁移到androidx.media3.session.MediaLibraryService
,并将使用MediaBrowserCompat.MediaItem
的代码迁移到androidx.media3.common.MediaItem
。 - MediaBrowserCompat(依赖于
androidx.media:media:1.4.3+
的android.support.v4.media.*
包)
将使用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
下的新包和模块结构。该脚本对您的项目应用一些验证检查,并在验证失败时打印警告。否则,它将在用 Java 或 Kotlin 编写的 Android Gradle 项目的资源中应用 重命名类和包的映射。
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
使用迁移脚本
从 GitHub 上与您已更新应用的版本相对应的 ExoPlayer 项目的标签中下载 迁移脚本
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 中选择 **文件 > 与 Gradle 文件同步项目**,然后 **构建 > 清理项目**,然后 **构建 > 重新构建项目**(在 Android Studio 的 '构建 - 构建输出' 选项卡 中监视构建)。
建议的后续步骤
- 解决 **关于使用不稳定 API 的错误的 opt-in**。
- **替换已弃用的 API 调用:**使用建议的替换 API。将指针悬停在 Android Studio 中的警告上,并查阅已弃用符号的 JavaDoc 以了解在给定调用中使用什么内容。
- **排序导入语句:**在 Android Studio 中打开项目,然后在项目查看器中右键单击包文件夹节点,并在包含已更改源文件的包上选择 **优化导入**。
将 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.4.1"
将
MediaSessionCompat
替换为 **androidx.media3.session.MediaSession
**。在您创建旧版
MediaSessionCompat
的代码位置,使用androidx.media3.session.MediaSession.Builder
**构建MediaSession
**。**传递播放器**以构建会话构建器。val player = ExoPlayer.Builder(context).build() mediaSession = MediaSession.Builder(context, player) .setSessionCallback(MySessionCallback()) .build()
根据应用需要实现
MySessionCallback
。这是可选的。如果您希望允许控制器向播放器添加媒体项,请实现MediaSession.Callback.onAddMediaItems()
。它提供了各种当前和旧版 API 方法,这些方法以向后兼容的方式将媒体项添加到播放器以进行播放。这包括 Media3 控制器的MediaController.set/addMediaItems()
方法,以及旧版 API 的TransportControls.prepareFrom*/playFrom*
方法。可以在 会话演示应用的PlaybackService
中 找到onAddMediaItems
的示例实现。在迁移前销毁会话的代码位置释放媒体会话
mediaSession?.run { player.release() release() mediaSession = null }
MediaSessionConnector
在 Media3 中的功能
下表显示了处理以前在 MediaSessionConnector
中实现的功能的 Media3 API。
MediaSessionConnector | AndroidX Media3 |
---|---|
CustomActionProvider |
MediaSession.Callback.onCustomCommand()/ MediaSession.setCustomLayout() |
PlaybackPreparer |
MediaSession.Callback.onAddMediaItems() (prepare() 在内部调用) |
QueueNavigator |
ForwardingPlayer |
QueueEditor |
MediaSession.Callback.onAddMediaItems() |
RatingCallback |
MediaSession.Callback.onSetRating() |
PlayerNotificationManager |
DefaultMediaNotificationProvider/ MediaNotification.Provider |
将 MediaBrowserService
迁移到 MediaLibraryService
AndroidX Media3 引入了 MediaLibraryService
,它取代了 MediaBrowserServiceCompat
。 MediaLibraryService
及其父类 MediaSessionService
的 JavaDoc 提供了有关 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.4.1"
将您的服务更改为继承自
MediaLibraryService
而不是MediaBrowserService
。如前所述,MediaLibraryService
与旧版MediaBrowserService
兼容。因此,服务提供给客户端的更广泛的 API 仍然相同。因此,应用很可能可以保留实现MediaBrowserService
所需的大部分逻辑,并将其适配到新的MediaLibraryService
。与旧版
MediaBrowserServiceCompat
相比,主要区别如下:实现服务生命周期方法:服务本身需要重写的方法是
onCreate/onDestroy
,应用在其中分配/释放库会话、播放器和其他资源。除了标准的服务生命周期方法外,应用还需要重写onGetSession(MediaSession.ControllerInfo)
以返回在onCreate
中构建的MediaLibrarySession
。实现 MediaLibraryService.MediaLibrarySessionCallback:构建会话需要一个
MediaLibraryService.MediaLibrarySessionCallback
,它实现实际的域 API 方法。因此,您将重写MediaLibrarySession.Callback
的方法,而不是重写旧版服务的 API 方法。然后使用回调来构建
MediaLibrarySession
。mediaLibrarySession = MediaLibrarySession.Builder(this, player, MySessionCallback()) .build()
在 API 文档中查找 MediaLibrarySessionCallback 的完整 API。
实现
MediaSession.Callback.onAddMediaItems()
:回调onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>)
用于各种当前和旧版 API 方法,这些方法以向后兼容的方式将媒体项添加到播放器以进行播放。这包括 Media3 控制器MediaController.set/addMediaItems()
方法以及旧版 API 的TransportControls.prepareFrom*/playFrom*
方法。可以在 会话演示应用的PlaybackService
中 找到回调的示例实现。AndroidX Media3 使用
androidx.media3.common.MediaItem
而不是 MediaBrowserCompat.MediaItem 和 MediaMetadataCompat。与旧版类相关的代码部分需要相应地更改或映射到 Media3MediaItem
。一般的异步编程模型更改为
Futures
,而不是MediaBrowserServiceCompat
的可分离Result
方法。您的服务实现可以返回异步ListenableFuture
,而不是分离结果或 返回立即 Future 以直接返回值。
删除 PlayerNotificationManager
MediaLibraryService
自动支持媒体通知,并且在使用 MediaLibraryService
或 MediaSessionService
时可以删除 PlayerNotificationManager
。
应用可以通过在 onCreate()
中设置自定义 MediaNotification.Provider
来自定义通知,该自定义项替换了 DefaultMediaNotificationProvider
。然后,MediaLibraryService
会根据需要将服务置于前台。
通过重写 MediaLibraryService.updateNotification()
,应用可以进一步完全控制发布通知以及根据需要启动/停止前台服务。
迁移使用 MediaBrowser 的客户端代码
在 AndroidX Media3 中,MediaBrowser
实现 MediaController/Player
接口,除了浏览媒体库外,还可以用于控制媒体播放。如果您必须在旧版环境中创建 MediaBrowserCompat
和 MediaControllerCompat
,则只需在 Media3 中使用 MediaBrowser
即可完成相同操作。
MediaBrowser
可以构建并等待与服务的连接建立。
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)
}
查看 在媒体会话中控制播放,了解如何在后台创建 MediaController
以控制播放。
后续步骤和清理
不稳定 API 错误
迁移到 Media3 后,您可能会看到有关不稳定 API 用法的 lint 错误。这些 API 可以安全使用,lint 错误是我们新的二进制兼容性保证的副产品。如果您不需要严格的二进制兼容性,则可以使用 @OptIn
注解安全地抑制这些错误。
背景
ExoPlayer v1 和 v2 都没有提供关于后续版本之间库的二进制兼容性的严格保证。ExoPlayer API 表面在设计上非常庞大,以便允许应用自定义播放的几乎每个方面。ExoPlayer 的后续版本偶尔会引入符号重命名或其他重大更改(例如,接口上的新必需方法)。在大多数情况下,这些中断通过在弃用旧符号的同时引入新符号来缓解,以使开发人员有时间迁移其用法,但这并非总是可能的。
这些重大更改导致 ExoPlayer v1 和 v2 库用户遇到两个问题:
- 从 ExoPlayer 版本升级可能会导致代码停止编译。
- 直接和通过中间库依赖于 ExoPlayer 的应用必须确保两个依赖项的版本相同,否则二进制不兼容性可能会导致运行时崩溃。
Media3 中的改进
Media3 保证 API 表面子集的二进制兼容性。不保证二进制兼容性的部分用 @UnstableApi
标记。为了使这种区别更加清晰,除非使用 @OptIn
进行注释,否则不稳定 API 符号的使用会生成 lint 错误。
从 ExoPlayer v2 迁移到 Media3 后,您可能会看到很多不稳定的 API lint 错误。这可能会让您觉得 Media3 比 ExoPlayer v2 “不稳定”。情况并非如此。“不稳定”的 Media3 API 部分具有与 ExoPlayer v2 API 表面的 **整体** 相同的稳定性级别,并且 ExoPlayer v2 完全无法获得稳定的 Media3 API 表面的保证。区别仅仅在于 lint 错误现在会提醒您不同级别的稳定性。
处理不稳定的 API lint 错误
有关如何使用 @OptIn
注释 Java 和 Kotlin 中不稳定 API 的用法的详细信息,请参阅 有关这些 lint 错误的故障排除部分。
已弃用的 API
您可能会注意到 Android Studio 中已弃用的 API 调用被删除线划掉。我们建议使用相应的替代方法替换这些调用。将鼠标悬停在符号上以查看 JavaDoc,该文档说明了要使用哪个 API 代替。
代码示例和演示应用
- AndroidX Media3 会话演示应用(移动设备和 WearOS)
- 自定义操作
- 系统 UI 通知、MediaButton/BT
- Google 助理播放控制
- UAMP:Android 媒体播放器(分支 media3)(移动设备、AutomotiveOS)
- 系统 UI 通知、MediaButton/BT、播放恢复
- Google 助理/WearOS 播放控制
- AutomotiveOS:自定义命令和登录