Jetpack Media3 定义了一个 Player
接口,其中列出了基本功能
来播放视频和音频文件。ExoPlayer
是默认实现
该接口位于 Media3 中我们建议使用 ExoPlayer,因为它提供了
功能全面,涵盖大多数播放用例,
以处理您可能遇到的任何其他用例。ExoPlayer 还
摆脱设备和操作系统碎片化问题,让您的代码以一致的方式运行
在整个 Android 生态系统中ExoPlayer 包含:
- 支持播放列表
- 支持各种渐进式和自适应流式传输 格式
- 同时支持客户端和服务器端广告插播
- 支持受 DRM 保护的播放
本页将为您介绍构建播放 如需了解更多详情,您可以参阅关于 Media3 ExoPlayer。
使用入门
首先,添加对 ExoPlayer、UI 和 Jetpack Media3:
implementation "androidx.media3:media3-exoplayer:1.4.1" implementation "androidx.media3:media3-ui:1.4.1" implementation "androidx.media3:media3-common:1.4.1"
根据您的用例,您可能还需要 Media3、
(例如 exoplayer-dash
),以 DASH 格式播放视频流。
请务必将 1.4.1
替换为您偏好的
库。您可以参阅版本说明
以查看最新版本。
创建媒体播放器
对于 Media3,您可以使用包含的 Player
实现
接口、ExoPlayer
,您也可以构建自己的自定义实现。
创建 ExoPlayer
如需创建 ExoPlayer
实例,最简单的方法是如下所示:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
您可以通过onCreate()
Activity
、Fragment
或 Service
。
Builder
包括
一系列您可能感兴趣的自定义选项,例如:
setAudioAttributes()
用于配置音频焦点处理setHandleAudioBecomingNoisy()
用于配置音频输出设备断开连接时的播放行为setTrackSelector()
配置轨道选择
Media3 提供了一个 PlayerView
界面组件,您可以将该组件添加到应用的
布局文件。此组件封装了用于播放的 PlayerControlView
控件,SubtitleView
用于显示字幕,Surface
用于渲染
视频。
准备播放器
将媒体内容添加到以下播放列表:
例如通过
setMediaItem()
和 addMediaItem()
。
然后,调用 prepare()
以
开始加载媒体并获取必要的资源。
您不应在应用处于前台之前执行这些步骤。如果您的
播放器位于 Activity
或 Fragment
中,这意味着要为
onStart()
生命周期方法(在 API 级别 24 及更高级别上,或者 onResume()
)
Lifecycle 方法。对于 Service
中的播放器,
可以在 onCreate()
中进行准备。
控制播放器
播放器准备就绪后,您可以通过调用方法来控制播放。 例如:
play()
和pause()
以开始和暂停播放seekTo()
可跳转到 当前媒体项中的位置seekToNextMediaItem()
和seekToPreviousMediaItem()
可浏览播放列表
界面组件(例如 PlayerView
或 PlayerControlView
)将更新
会相应地发生调整
释放播放器
播放可能需要供应量有限的资源,例如视频
因此请务必调用 release()
,以便在不再需要该播放器时释放资源。
如果您的播放器处于 Activity
或 Fragment
中,请在
onStop()
生命周期方法(在 API 级别 24 及更高级别上,或者 onPause()
)
方法。对于 Service
中的播放器,您可以
在 onDestroy()
中释放。
使用媒体会话管理播放
在 Android 上,媒体会话提供了一种与媒体互动的标准化方式 来扩展容器。将媒体会话连接到播放器 让您可以在外部通告自己的媒体播放,并接收播放 来自外部来源的命令,例如用于集成 移动设备和大型设备上的系统媒体控件 屏幕设备。
如需使用媒体会话,请添加对 Media3 Session 模块的依赖项:
implementation "androidx.media3:media3-session:1.4.1"
创建媒体会话
您可以在初始化播放器后创建 MediaSession
,如下所示:
Kotlin
val player = ExoPlayer.Builder(context).build() val mediaSession = MediaSession.Builder(context, player).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build(); MediaSession mediaSession = new MediaSession.Builder(context, player).build();
Media3 会自动将 Player
的状态与
MediaSession
。这适用于所有 Player
实现,包括
ExoPlayer
、CastPlayer
或
自定义实现
向其他客户端授予控制权
客户端应用可以实现媒体控制器
来控制媒体会话的播放。要接收这些请求,请将
Callback 对象时,
构建您的 MediaSession
。
当控制器即将连接到您的媒体会话时,
onConnect()
方法。您可以使用提供的 ControllerInfo
然后决定是否接受
或拒绝
请求。您可以在 Media3 Session 演示版应用中查看相关示例。
连接后,控制器即可向会话发送播放命令。通过
然后将这些命令委托给玩家。播放和播放列表
Player
接口中定义的命令由
会话。
例如,您可以使用其他回调方法处理对
自定义播放命令
和修改播放列表。这些回调同样包含一个 ControllerInfo
对象,因此您可以
可以逐个请求确定访问权限控制。
正在后台播放媒体内容
例如,在应用未在前台运行时继续播放媒体内容
播放音乐、有声读物或播客,即使用户未安装您的应用也无妨
您的 Player
和 MediaSession
应封装在
前台服务。Media3 为
MediaSessionService
接口实现这一目的。
实现 MediaSessionService
创建一个扩展 MediaSessionService
的类,并实例化
onCreate()
生命周期方法中的 MediaSession
。
Kotlin
class PlaybackService : MediaSessionService() { private var mediaSession: MediaSession? = null // Create your Player and MediaSession in the onCreate lifecycle event override fun onCreate() { super.onCreate() val player = ExoPlayer.Builder(this).build() mediaSession = MediaSession.Builder(this, player).build() } // Remember to release the player and media session in onDestroy override fun onDestroy() { mediaSession?.run { player.release() release() mediaSession = null } super.onDestroy() } }
Java
public class PlaybackService extends MediaSessionService { private MediaSession mediaSession = null; @Override public void onCreate() { super.onCreate(); ExoPlayer player = new ExoPlayer.Builder(this).build(); mediaSession = new MediaSession.Builder(this, player).build(); } @Override public void onDestroy() { mediaSession.getPlayer().release(); mediaSession.release(); mediaSession = null; super.onDestroy(); } }
在清单中,包含 MediaSessionService
intent 的 Service
类
过滤并请求 FOREGROUND_SERVICE
权限以运行前台
服务:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaSessionService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
最后,在您创建的类中,替换 onGetSession()
方法以控制
客户端访问您的媒体会话的权限。返回一个 MediaSession
以接受
连接请求,或返回 null
以拒绝请求。
Kotlin
// This example always accepts the connection request override fun onGetSession( controllerInfo: MediaSession.ControllerInfo ): MediaSession? = mediaSession
Java
@Override public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) { // This example always accepts the connection request return mediaSession; }
连接到界面
现在,您的媒体会话位于 Service
(与 Activity
或
Fragment
,那么您可以使用 MediaController
来关联
将它们放在一起在 Activity
或 Fragment
的 onStart()
方法中,使用
在界面中,为您的 MediaSession
创建 SessionToken
,然后使用 SessionToken
来构建 MediaController
。构建 MediaController
异步执行。
Kotlin
override fun onStart() { val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java)) val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync() controllerFuture.addListener( { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()) }, MoreExecutors.directExecutor() ) }
Java
@Override public void onStart() { SessionToken sessionToken = new SessionToken(this, new ComponentName(this, PlaybackService.class)); ListenableFuture<MediaController> controllerFuture = new MediaController.Builder(this, sessionToken).buildAsync(); controllerFuture.addListener(() -> { // Call controllerFuture.get() to retrieve the MediaController. // MediaController implements the Player interface, so it can be // attached to the PlayerView UI component. playerView.setPlayer(controllerFuture.get()); }, MoreExecutors.directExecutor()) }
MediaController
会实现 Player
接口,因此您可以使用同样的
方法(例如 play()
和 pause()
)来控制播放。与其他类似
组件之前,请务必释放 MediaController
。
例如 Activity
的 onStop()
生命周期方法,只需调用
MediaController.releaseFuture()
。
发布通知
需要前台服务才能发布处于活跃状态的通知。答
MediaSessionService
会自动创建
以下账号的MediaStyle
通知:
以 MediaNotification
形式提供给您。
要提供自定义通知,请创建一个
MediaNotification.Provider
与DefaultMediaNotificationProvider.Builder
共享
也可以创建提供程序接口的自定义实现添加您的
将提供商与您的 MediaSession
相关联,具体如下:
setMediaNotificationProvider
。
宣传你的内容库
MediaLibraryService
在 MediaSessionService
的基础上构建,通过允许客户端构建
浏览应用提供的媒体内容。客户端应用实现了
MediaBrowser
即可互动
与您的MediaLibraryService
共享。
实现 MediaLibraryService
与实现
MediaSessionService
,只不过在 onGetSession()
中,您应返回
MediaLibrarySession
,而不是 MediaSession
。与
MediaSession.Callback
,MediaLibrarySession.Callback
包含
方法,这些方法允许浏览器客户端浏览您的
图书馆服务
与 MediaSessionService
类似,在MediaLibraryService
清单并请求 FOREGROUND_SERVICE
权限以运行前台
服务:
<service
android:name=".PlaybackService"
android:foregroundServiceType="mediaPlayback"
android:exported="true">
<intent-filter>
<action android:name="androidx.media3.session.MediaLibraryService"/>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
上面的示例包含 MediaLibraryService
和
以及旧版 MediaBrowserService
(为了向后兼容)。通过
额外的 intent 过滤器支持使用 MediaBrowserCompat
API 的客户端应用
以便识别您的Service
。
借助 MediaLibrarySession
,您可以在树中提供内容库
具有单个根 MediaItem
。树中的每个 MediaItem
任意数量的子 MediaItem
节点。你可以提供其他根,或
不同的树。例如,您构建的树
如果客户再次寻找推荐的媒体项列表,
包含根 MediaItem
和单级子 MediaItem
节点,
而返回其他客户端应用的树可能代表
一个完整的内容库
创建 MediaLibrarySession
MediaLibrarySession
扩展了 MediaSession
API,以添加内容浏览 API。与
MediaSession
回调;
MediaLibrarySession
回调
添加了如下方法:
onGetLibraryRoot()
当客户端请求内容树的根MediaItem
时onGetChildren()
当客户端请求内容树中MediaItem
的子项时onGetSearchResult()
当客户端从给定网页的内容树中请求搜索结果时, 查询
相关回调方法将包含 LibraryParams
对象包含有关客户端应用的内容树类型的额外信号
感兴趣的主题。