创新方案
在 Android 应用中使用 Jetpack…
当需要为 Android 应用新增 Cast 投屏功能,或把旧版 Google Cast SDK 迁移到 Jetpack Media3 Cast 时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Android 应用中使用 Jetp通用
解决思路
- 确保 Jetpack Media3 版本 >= 1.9.0,低于该版本不支持 Cast。
- 在 app 级构建文件中声明 media3-cast 依赖,版本 1.9.0 或更高,例如 implementation("androidx.media3:media3-cast:1.11.0")。
- 确保存在所需的 Media3 依赖:androidx.media3:media3-exoplayer、androidx.media3:media3-session、androidx.media3:media3-ui-compose;如果应用使用旧版 View,则额外添加 media3-ui。
- 强制所有 Media3 依赖使用相同版本。
- 以《Getting started with CastPlayer》中 “Add build dependencies” 一节为配置的权威来源。
- 对于尚无 Cast 集成的应用:确认不存在旧版 Cast SDK(libs.play.services.cast.framework)。
- 如果是从旧版 Cast SDK 迁移:先添加 Media3 Cast 依赖,此阶段保持现有旧版依赖不变,以免编译错误。
- 在 manifest 的 <application> 标签内声明 Cast options provider。
- 默认使用 DefaultCastOptionsProvider;仅在明确要求时才声明自定义 OptionsProvider。
- 确保存在 INTERNET 权限,不要添加任何不必要的权限。
- 如果是从旧版 Cast SDK 迁移:不要删除已有的自定义 options provider 文件或 manifest 条目。
- 在应用的 MediaSessionService(或 MediaLibraryService)的 onCreate() 方法中初始化 ExoPlayer 和 CastPlayer。
- 默认使用 CastPlayer,除非明确要求使用 RemoteCastPlayer。
- 对于 CastPlayer,直接把实例传给 MediaSession.Builder。
- 替换所有旧版 forwarding player 包装器。
- 迁移期间不要删除旧版类文件,以免编译错误。
- 仅在用户明确要求时使用 RemoteCastPlayer。
- 使用 RemoteCastPlayer 时,用 localPlayer 初始化 MediaSession,并在 RemoteCastPlayer 上设置 SessionAvailabilityListener,在 Cast 会话可用性变化时转移播放状态(onCastSessionAvailable 时从 localPlayer 转移到 remotePlayer,onCastSessionUnavailable 时反向转移)。
- 在转移播放状态时,若前一播放器有媒体项,则用 PlayerTransferState.builderFromPlayer(previousPlayer) 构建转移状态;若前一播放器处于 STATE_ENDED 或当前位置为 C.TIME_END_OF_SOURCE,则把当前媒体项索引和位置都设为 0;然后 setToPlayer(newPlayer),并 stop 和 clearMediaItems 前一播放器、prepare 新播放器、通过 mediaSession?.setPlayer(newPlayer) 切换播放器。
- Compose UI:参考《Getting started with CastPlayer》中 “Add a MediaRouteButton Composable to the Player” 一节。
- Compose UI:使用 androidx.media3.cast 包中的 MediaRouteButton composable。
- Compose UI:不要在 Compose UI 层级中使用 AndroidView。
- Compose UI:把 MediaRouteButton 放在播放控件旁边的区域,不要藏在系统 UI 后面。
- Compose UI:不要用 PlayerSurface 做自定义播放器 UI,改用 Material3 的 Player composable。
- Compose UI:在播放位置切换时强制重组以保证 UI 同步,使用基于 DeviceInfo 变化的 key 约束(例如 key(deviceInfo) { PlayerScreen(player = activePlayer) }),并通过 Player.Listener 的 onDeviceInfoChanged 更新 deviceInfo。
- View UI:参考《Getting started with CastPlayer》中 “Add UI elements” 一节。
- View UI:投屏 Activity 必须继承 AppCompatActivity 或 FragmentActivity,并使用 Theme.AppCompat 的派生主题。
- View UI:如果把 MediaRouteButton 加到 options menu,确保 AppCompat 主题有可见的 ActionBar。
- View UI:把所有 CastButtonFactory 的实例和 import 替换为 MediaRouteButtonFactory。
- View UI:在 onDeviceInfoChanged 事件中重新绑定 PlayerView.player 引用,以避免黑屏或 UI 卡死:先把 playerView.player 置为 null(绕过 PlayerView.setPlayer() 的实例相等检查),再重新赋值为 controller。
- 迁移到 Compose 时:不要用 AndroidView 包装旧版 PlayerView。
- 迁移到 Compose 时:按《Getting started with CastPlayer》实现 Material3 的 Player composable 和 MediaRouteButton composable。
- 迁移到 Compose 时:移除旧版 XML 布局声明、menu 文件和 View 组件引用。
- 清理旧版 Cast SDK 代码时:不要直接执行清理,仅在用户明确要求时才移除旧版文件和依赖。
- 清理时移除旧版 GMS Cast SDK(libs.play.services.cast.framework)和 MediaRouter(libs.androidx.mediarouter)依赖。
- 清理时如果采用 DefaultCastOptionsProvider,则删除自定义 OptionsProvider 类和 manifest 条目。
- 清理时如果存在旧版 MediaTransferReceiver manifest 声明,则移除。
- 清理时移除所有对旧版 Cast SDK 组件的引用,例如旧版 helper 包装器、forwarding player 和 RemoteMediaClient 接口。
- 如果已完成 Compose 迁移,清理时删除旧版 View XML 布局、menu 文件和对 PlayerView 的引用。
适用边界 · 注意事项
- Jetpack Media3 版本低于 1.9.0 时不可用。
- 用户未明确要求时,不要使用旧版 Google Cast SDK(其处于维护模式),也不要使用 RemoteCastPlayer。
- 用户未明确要求时,不要执行旧版 Cast SDK 代码清理。