AndroidX Media3 迁移指南

目前使用独立版 com.google.android.exoplayer2 的应用 库,androidx.media 应迁移到 androidx.media3。使用 迁移脚本,用于迁移 Gradle build 文件、Java 和 Kotlin 源文件和 ExoPlayer 中的 XML 布局文件 2.19.1 到 AndroidX Media3 1.1.1

概览

在迁移之前,请查看以下部分,详细了解 新 API 的优势、要迁移的 API 以及相关前提条件 应用的项目应满足此要求。

为什么要迁移到 Jetpack Media3

  • 它是 ExoPlayer 的新家,而 com.google.android.exoplayer2 已停售。
  • 跨组件/进程访问 Player APIMediaBrowser/MediaController
  • 使用 MediaSessionMediaController API。
  • 通过精细的访问权限控制通告播放功能。
  • 通过移除 MediaSessionConnector简化应用 PlayerNotificationManager
  • 使用 media-compat 客户端 API 向后兼容MediaBrowserCompat/MediaControllerCompat/MediaMetadataCompat

用于迁移到 AndroidX Media3 的媒体 API

  • 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.MediaItemandroidx.media3.common.MediaItem
  • MediaBrowserCompat(具体取决于 android.support.v4.media.* 个软件包,共 androidx.media:media:1.4.3+
    使用 MediaBrowserCompatMediaControllerCompat 使用 androidx.media3.session.MediaBrowser androidx.media3.common.MediaItem

前提条件

  1. 确保您的项目受源代码控制

    确保您可以轻松还原通过脚本迁移工具应用的更改。 如果您还没有对您的项目进行源代码控制,现在正是合适的时机 我们先来看一下如果出于某种原因您不想这样做, 开始迁移前项目的备份副本。

  2. 更新应用

    • 我们建议您更新项目以使用 最新版本的 ExoPlayer 库,并移除所有 对已弃用的方法的调用。如果您希望 使用脚本进行迁移,您需要与 您要更新的版本。

    • compileSdkVersion 提高到至少 32

    • 将 Gradle 和 Android Studio Gradle 插件升级到最新版本 版本。对于 实例:

      • Android Gradle 插件版本:7.1.0
      • Gradle 版本:7.4
    • 替换所有使用星号的通配符 import 语句 (*) 并使用完全限定的 import 语句:删除通配符 import 语句并使用 Android Studio 导入完全限定的 语句(F2 - Alt/Enter、F2 - Alt/Enter...)。

    • com.google.android.exoplayer2.PlayerView 迁移到 com.google.android.exoplayer2.StyledPlayerView。这是必要的 因为没有等效的 com.google.android.exoplayer2.PlayerView(在 AndroidX Media3 中)。

迁移支持脚本的 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

使用迁移脚本

  1. 从 ExoPlayer 项目的标记下载迁移脚本 GitHub 的下列版本:

    curl -o media3-migration.sh \
      "https://raw.githubusercontent.com/google/ExoPlayer/r2.19.1/media3-migration.sh"
    
  2. 将脚本设为可执行:

    chmod 744 media3-migration.sh
    
  3. 使用 --help 运行脚本以了解相关选项。

  4. 使用 -l 运行脚本,列出为新标签选择的文件集 迁移(使用 -f 强制列出而不显示警告):

    ./media3-migration.sh -l -f /path/to/gradle/project/root
    
  5. 使用 -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 选项运行脚本后,完成以下手动步骤:

  1. 检查脚本对代码有何更改:使用差异工具进行修复 潜在问题(如果您认为脚本存在 在没有传递 -f 选项的情况下引入的一般性问题)。
  2. 构建项目:使用 ./gradlew clean build 或在 Android 中构建 在 Studio 中依次选择文件 >Sync Project with Gradle Files,然后依次选择 Build > 清理项目,然后点击构建 >重新构建项目(在 “构建 - 构建输出”标签页

建议的后续步骤:

  1. 解决选择接受与使用不稳定 API 相关的错误的问题。
  2. 替换已弃用的 API 调用:使用建议的替代 API。 将指针悬停在 Android Studio 中的警告上,并查阅 JavaDoc 来找出用于代替指定调用的内容。
  3. 对 import 语句进行排序:在 Android Studio 中打开项目,然后 右键点击项目查看器中的软件包文件夹节点,然后选择 对包含已更改的源文件的软件包优化导入

MediaSessionConnector 替换为 androidx.media3.session.MediaSession

在旧版 MediaSessionCompat 环境中,MediaSessionConnector 负责将播放器的状态与会话的状态同步 以及接收来自需要委托给相应控制器的命令 播放器方法。对于 AndroidX Media3,此操作由 MediaSession 直接完成 而无需使用连接器。

  1. 移除 MediaSessionConnector 的所有引用和用法:如果您在 用于迁移 ExoPlayer 类和软件包的自动化脚本, 可能导致您的代码处于不可编译状态, 为无法解析的MediaSessionConnector。Android Studio 将 会在您尝试构建或启动应用时向您显示损坏的代码。

  2. 在维护依赖项的 build.gradle 文件中,添加 AndroidX Media3 会话模块的实现依赖项,并移除 旧版依赖项:

    implementation "androidx.media3:media3-session:1.4.0"
    
  3. MediaSessionCompat 替换为 androidx.media3.session.MediaSession

  4. 在创建旧版 MediaSessionCompat 的代码网站上,使用 androidx.media3.session.MediaSession.Builder构建 MediaSession传递玩家以构建会话构建器。

    val player = ExoPlayer.Builder(context).build()
    mediaSession = MediaSession.Builder(context, player)
        .setSessionCallback(MySessionCallback())
        .build()
    
  5. 根据应用的要求实现 MySessionCallback。此操作为可选项。如果 您希望允许控制器向播放器添加媒体项, MediaSession.Callback.onAddMediaItems()。它提供了各种现行和 传统 API 方法,这些方法将媒体项添加到播放器,以便在 向后兼容的方式这包括 MediaController.set/addMediaItems() 方法,如 以及 TransportControls.prepareFrom*/playFrom* 方法。onAddMediaItems 的实现示例如下: 可在会话演示应用的 PlaybackService 中找到

  6. 在销毁会话的代码站点释放媒体会话 迁移前:

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

Media3 中的 MediaSessionConnector 功能

下表显示了用于处理功能的 Media3 API 之前在 MediaSessionConnector 中实现。

MediaSessionConnectorAndroidX 媒体 3
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,用于替换 MediaBrowserServiceCompatMediaLibraryService 及其超类的 JavaDoc MediaSessionService 类对 API 和 服务的异步编程模型。

MediaLibraryService 向后兼容 MediaBrowserService。使用 MediaBrowserCompatMediaControllerCompat,连接时无需更改代码即可继续工作 转换为 MediaLibraryService。对于客户而言,您的应用是否 使用 MediaLibraryService 或旧版 MediaBrowserServiceCompat

<ph type="x-smartling-placeholder">
</ph> 包含服务、activity 和外部应用的应用组件示意图。
图 1:媒体应用组件概览
  1. 要实现向后兼容性,您需要同时注册这两项服务 与您的服务交互。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>
    
  2. 在维护依赖项的 build.gradle 文件中,添加 AndroidX Media3 会话模块的实现依赖项 移除旧版依赖项:

    implementation "androidx.media3:media3-session:1.4.0"
    
  3. 将您的服务更改为从MediaLibraryService(而不是 MediaBrowserService 如前所述,MediaLibraryService 与旧版兼容 MediaBrowserService。相应地,该服务所属的范围更广的 API 仍然保持不变因此应用可能会 实现 MediaBrowserService 所需的大部分逻辑 并针对新的 MediaLibraryService 对其进行调整。

    与旧版的主要差异 MediaBrowserServiceCompat 如下所示:

    • 实现服务生命周期方法onCreate/onDestroy,其中 应用分配/释放库会话、播放器和其他 资源。除了标准服务生命周期方法之外,应用 需要替换 onGetSession(MediaSession.ControllerInfo) 才能返回 在 onCreate 中构建的 MediaLibrarySession

    • 实现 MediaLibraryService.MediaLibrarySessionCallback:构建 会话需要 MediaLibraryService.MediaLibrarySessionCallback 实际的域 API 方法。因此,您不必覆盖 您需要覆盖 MediaLibrarySession.Callback

      然后,该回调将用于构建 MediaLibrarySession

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

      在 API 中查找 MediaLibrarySessionCallback 的完整 API 文档。

    • 实现 MediaSession.Callback.onAddMediaItems():回调 提供 onAddMediaItems(MediaSession, ControllerInfo, List<MediaItem>) 次 可将媒体项添加到播放器的各种现有和旧版 API 方法 以便以向后兼容的方式播放这包括 MediaController.set/addMediaItems() 方法; 以及 TransportControls.prepareFrom*/playFrom* 方法。回调的实现示例可以 可在会话演示应用的 PlaybackService 中找到

    • AndroidX Media3 改为使用 androidx.media3.common.MediaItemMediaBrowserCompat.MediaItemMediaMetadataCompat。零件 与旧版类关联的代码,需要相应地更改 或映射到 Media3 MediaItem

    • 常规异步编程模型更改为 Futures 这与Result MediaBrowserServiceCompat。您的服务实现可以返回一个 异步 ListenableFuture,而不是分离结果或 返回一个立即 Future 以直接返回值

移除 PlayerNotificationManager

MediaLibraryService 自动支持媒体通知,并且 PlayerNotificationManager可以在使用MediaLibraryServiceMediaSessionService

应用可以通过设置自定义 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 Surface 大体设计,让应用可以自定义几乎每个方面的 。后续版本的 ExoPlayer 偶尔会引入符号 重命名或其他重大更改(例如接口上所需的新方法)。在 在大多数情况下,通过引入新符号 同时弃用几个版本的旧符号 但有时无法做到这一点

这些破坏性更改给 ExoPlayer v1 的用户带来了两个问题 和 v2 库:

  1. 升级到 ExoPlayer 版本可能会导致代码停止编译。
  2. 直接依赖于 ExoPlayer 以及通过中间组件依赖于 ExoPlayer 的应用 库必须确保两个依赖项的版本相同, 否则,二进制文件不兼容可能会导致运行时崩溃。

Media3 中的改进

Media3 可保证 API Surface 的子集的二进制文件兼容性。通过 保证二进制兼容性的部分带有 @UnstableApi。为了明确这一区别,“不稳定”的用法 除非带有 @OptIn 注解,否则 API 符号会生成 lint 错误。

从 ExoPlayer v2 迁移到 Media3 后,您可能会看到许多不稳定的 API lint 错误。这可能会使 Media3 看起来“不太稳定”与 ExoPlayer 相比 v2。事实并非如此。“不稳定”在 Media3 API 中, ExoPlayer v2 API Surface 的整个稳定性级别,以及 ExoPlayer v2 无法保证稳定 Media3 API Surface 全部。不同之处在于,lint 错误现在会提醒您 稳定性。

处理不稳定的 API lint 错误

请参阅这些 lint 错误的问题排查部分,详细了解如何 为 Java 和 Kotlin 使用不稳定 API 添加了 @OptIn 注解。

已弃用的 API

您可能会注意到,对已弃用 API 的调用在 Android 中带有删除线 Studio。我们建议您改用适当的替代调用替代此类调用。 将鼠标悬停在该符号上即可查看 JavaDoc,其中会说明应改用哪个 API。

<ph type="x-smartling-placeholder">
</ph> 屏幕截图:如何使用已废弃方法的替代方法显示 JavaDoc
图 3:Android Studio 中的 JavaDoc 提示针对任何已弃用的符号提供了替代建议。

代码示例和演示应用

  • AndroidX Media3 会话演示应用(移动设备和 WearOS) <ph type="x-smartling-placeholder">
      </ph>
    • 自定义操作
    • 系统界面通知、MediaButton/BT
    • Google 助理播放控制
  • UAMP:Android Media Player(分支 media3)(移动设备、AutoOS) <ph type="x-smartling-placeholder">
      </ph>
    • 系统界面通知、MediaButton/BT、继续播放
    • Google 助理/Wear OS 播放控制
    • AutomotiveOS:自定义命令和登录