目前使用独立 com.google.android.exoplayer2 库和 androidx.media 的应用应迁移到 androidx.media3。使用迁移脚本将 Gradle build 文件、Java 和 Kotlin 源文件以及 XML 布局文件从 ExoPlayer 2.19.1 迁移到 AndroidX Media3 1.1.1。
概览
在迁移之前,请查看以下部分,详细了解新 API 的优势、要迁移的 API 以及应用项目应满足的前提条件。
为何迁移到 Jetpack Media3
- 它是 ExoPlayer 的新平台,而
com.google.android.exoplayer2已停用。 - 使用
MediaBrowser/MediaController跨组件/进程访问 Player API。 - 使用
MediaSession和MediaControllerAPI 的扩展功能。 - 通过精细访问权限控制通告播放功能。
- 通过移除
MediaSessionConnector和PlayerNotificationManager来简化应用。 - 向后兼容 media-compat 客户端 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选项而引入的一般问题,请考虑提交bug)。 - 构建项目:使用
./gradlew clean build,或在 Android Studio 中依次选择 File > Sync Project with Gradle Files、Build > Clean project 和 Build > Rebuild project(在 Android Studio 的“Build - Build Output”标签页中监控构建过程)。
建议的后续步骤:
- 解决选择加入有关使用不稳定 API 的错误。
- 替换已废弃的 API 调用:使用建议的替代 API。 将指针悬停在 Android Studio 中的警告上,然后查阅已弃用符号的 JavaDoc,了解应使用什么来代替给定的调用。
- 对 import 语句进行排序:在 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 方法,这些方法以向后兼容的方式将媒体文件添加到播放器中进行播放。这包括 Media3 控制器的MediaController.set/addMediaItems()方法,以及旧版 API 的TransportControls.prepareFrom*/playFrom*方法。onAddMediaItems的实现示例可在会话演示应用的PlaybackService中找到。在迁移前销毁会话的代码位置释放媒体会话:
Kotlin
mediaSession?.run { player.release() release() mediaSession = null }
Java
if (mediaSession != null) { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; }
Media3 中的 MediaSessionConnector 功能
下表显示了用于处理之前在 MediaSessionConnector 中实现的功能的 Media3 API。
| 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。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.11.1"将您的服务更改为继承自
MediaLibraryService,而不是MediaBrowserService如前所述,MediaLibraryService与旧版MediaBrowserService兼容。因此,服务向客户端提供的更广泛的 API 仍然相同。因此,应用很可能可以保留实现MediaBrowserService所需的大部分逻辑,并将其调整为适应新的MediaLibraryService。与旧版
MediaBrowserServiceCompat相比,主要区别如下:实现服务生命周期方法:需要在服务本身上替换的方法是
onCreate/onDestroy,应用会在其中分配/释放媒体库会话、播放器和其他资源。除了标准服务生命周期方法之外,应用还需要替换onGetSession(MediaSession.ControllerInfo),以返回在onCreate中构建的MediaLibrarySession。实现 MediaLibraryService.MediaLibrarySessionCallback:构建会话需要一个实现实际网域 API 方法的
MediaLibraryService.MediaLibrarySessionCallback。因此,您将替换MediaLibrarySession.Callback的方法,而不是替换旧版服务的方法。然后,使用该回调来构建
MediaLibrarySession:Kotlin
mediaLibrarySession = MediaLibrarySession.Builder(context, player, MySessionCallback()).build()
Java
mediaLibrarySession = new MediaLibrarySession.Builder(context, player, new MySessionCallback()).build();
如需查看 MediaLibrarySessionCallback 的完整 API,请参阅 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。与
MediaBrowserServiceCompat的可分离Result方法相比,常规异步编程模型已更改为Futures。您的服务实现可以返回异步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 并等待与服务建立连接:
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 错误不稳定
迁移到 Media3 后,您可能会看到有关不稳定 API 使用情况的 lint 错误。
这些 API 可以安全使用,而 lint 错误是我们新的二进制文件兼容性保证的副产品。如果您不需要严格的二进制兼容性,则可以使用 @OptIn 注解安全地抑制这些错误。
背景
ExoPlayer v1 和 v2 均未对后续版本之间的库二进制兼容性提供严格保证。ExoPlayer API 接口在设计上非常大,以便应用能够自定义播放的几乎每个方面。后续版本的 ExoPlayer 偶尔会引入符号重命名或其他破坏性更改(例如,接口上新增了必需的方法)。在大多数情况下,这些破坏性更改通过引入新符号并弃用旧符号几个版本来缓解,以便开发者有时间迁移其用法,但这并非总是可行。
这些破坏性更改给 ExoPlayer v1 和 v2 库的用户带来了两个问题:
- 从 ExoPlayer 版本升级可能会导致代码停止编译。
- 如果应用同时直接依赖于 ExoPlayer 和通过中间库依赖于 ExoPlayer,则必须确保这两个依赖项的版本相同,否则二进制文件不兼容可能会导致运行时崩溃。
Media3 中的改进
Media3 可保证部分 API Surface 的二进制文件兼容性。不保证二进制文件兼容性的部分会标记为 @UnstableApi。为了明确区分,使用不稳定的 API 符号会生成 lint 错误,除非它们带有 @OptIn 注解。
从 ExoPlayer v2 迁移到 Media3 后,您可能会看到许多不稳定的 API lint 错误。这可能会让人觉得 Media3 不如 ExoPlayer v2 稳定。但其实不是这样。Media3 API 的“不稳定”部分与 ExoPlayer v2 API Surface 的整体具有相同的稳定性,而 ExoPlayer v2 根本不提供稳定的 Media3 API Surface 的保证。不同之处在于,现在 lint 错误会提醒您注意不同的稳定性级别。
处理不稳定的 API lint 错误
如需详细了解如何使用 @OptIn 为不稳定 API 的 Java 和 Kotlin 用法添加注解,请参阅有关这些 lint 错误的“问题排查”部分。
已弃用的 API
您可能会注意到,在 Android Studio 中,对已弃用 API 的调用会带有删除线。我们建议您将此类调用替换为适当的替代方案。 将鼠标悬停在符号上,即可查看 JavaDoc,其中会说明应改用哪个 API。
代码示例和演示应用
- AndroidX Media3 会话演示应用(移动设备和 WearOS)
- 自定义操作
- 系统界面通知、MediaButton/BT
- Google 助理播放控件
- UAMP:Android 媒体播放器(分支 media3)(移动设备、AutomotiveOS)
- 系统界面通知、MediaButton/BT、恢复播放
- Google 助理/WearOS 播放控件
- AutomotiveOS:自定义命令和登录