CastPlayer 是 Jetpack Media3 Player 實作項目,支援在本機播放內容,以及投放到支援 Cast 的遠端裝置。CastPlayer
可簡化在應用程式中新增 Cast 功能的程序,並提供豐富的功能,讓使用者在本地和遠端播放之間順暢切換。本指南說明如何將 CastPlayer 整合至媒體應用程式。
如要將 Cast 與其他平台整合,請參閱 Cast SDK。
取得支援 Cast 的裝置
如要測試 CastPlayer,您需要支援 Cast 的裝置。包括 Android TV、Chromecast、智慧音箱和智慧螢幕。確認裝置已設定完成,並連上與開發用行動裝置相同的 Wi-Fi 網路,以便探索裝置。
新增建構依附元件
如要開始使用 CastPlayer,請將 AndroidX Media3 和 CastPlayer 依附元件新增至應用程式模組的 build.gradle 檔案。
Kotlin
implementation("androidx.media3:media3-exoplayer:1.9.2")
implementation("androidx.media3:media3-ui:1.9.2")
implementation("androidx.media3:media3-session:1.9.2")
implementation("androidx.media3:media3-cast:1.9.2")
Groovy
implementation "androidx.media3:media3-exoplayer:1.9.2"
implementation "androidx.media3:media3-ui:1.9.2"
implementation "androidx.media3:media3-session:1.9.2"
implementation "androidx.media3:media3-cast:1.9.2"
設定 CastPlayer
如要設定 CastPlayer,請使用選項供應商更新 AndroidManifest.xml 檔案。
選項供應商
CastPlayer 需要選項供應器來設定其行為。如要進行基本設定,請將 DefaultCastOptionsProvider 新增至 AndroidManifest.xml 檔案。這會使用預設設定,包括預設接收器應用程式。
<application>
...
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="androidx.media3.cast.DefaultCastOptionsProvider" />
...
</application>
如要自訂設定,請實作自己的自訂 OptionsProvider。如要瞭解如何設定,請參閱 CastOptions 指南。
新增媒體轉移接收器
在資訊清單中新增 MediaTransferReceiver,系統 UI 就能在網路上探索支援 Cast 的裝置,並重新導向媒體,無須開啟應用程式活動。舉例來說,使用者可以透過媒體通知,變更播放應用程式媒體的裝置。
<application>
...
<receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />
...
</application>
建構 CastPlayer
如要使用 Cast 進行遠端播放,即使使用者未與應用程式的 Activity 互動 (例如透過系統媒體通知),應用程式也應能管理播放作業。因此,您應在服務 (例如 MediaSessionService 或 MediaLibraryService) 中建立 ExoPlayer (用於本機播放) 和 CastPlayer (用於遠端播放) 執行個體。首先,請建立 ExoPlayer 執行個體,然後在建構 CastPlayer 執行個體時,將 ExoPlayer 設為本機播放器執行個體。然後,你可以透過媒體通知或鎖定螢幕通知,在行動裝置和支援 Cast 的裝置之間切換媒體播放功能。當輸出路徑從本機變更為遠端,或從遠端變更為本機時,Media3 會使用「輸出切換器」功能處理播放器轉移作業。
Kotlin
override fun onCreate() { super.onCreate() val exoPlayer = ExoPlayer.Builder(context).build() val castPlayer = CastPlayer.Builder(context) .setLocalPlayer(exoPlayer) .build() mediaSession = MediaSession.Builder(context, castPlayer).build() }
Java
@Override public void onCreate() { super.onCreate(); ExoPlayer exoPlayer = new ExoPlayer.Builder(context).build(); CastPlayer castPlayer = new CastPlayer.Builder(context) .setLocalPlayer(exoPlayer) .build(); mediaSession = new MediaSession.Builder( /* context= */ context, /* player= */ castPlayer).build(); }
新增 UI 元素
在應用程式的 UI 中新增 MediaRouteButton。輕觸 MediaRouteButton 會開啟對話方塊,顯示網路上可用的 Cast 裝置清單。使用者選取裝置後,媒體播放作業就會從行動裝置轉移至所選接收器裝置。本節說明如何新增按鈕及監聽事件,以便在播放作業於本機和遠端裝置之間切換時更新 UI。
設定 MediaRouteButton
將 MediaRouteButton 新增至活動 UI 的方式有四種。最適合的選擇取決於應用程式的設計和需求。
- Compose UI:新增按鈕可組合函式。
- 「檢視」使用者介面:
- 將按鈕新增至應用程式列選單。
- 在
PlayerView中新增按鈕。 - 將按鈕新增為標準
View。
將可組合函式 MediaRouteButton 新增至播放器
您可以將 MediaRouteButton 可組合函式新增至播放器的 UI。詳情請參閱 Compose 指南。
Kotlin
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeOut import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier import androidx.media3.cast.MediaRouteButton @Composable fun PlayerComposeView(player: Player, modifier: Modifier = Modifier) { var controlsVisible by remember { mutableStateOf(false) } Box( modifier = modifier.clickable { controlsVisible = true }, contentAlignment = Alignment.Center, ) { PlayerSurface(player = player, modifier = modifier) AnimatedVisibility(visible = controlsVisible, enter = fadeIn(), exit = fadeOut()) { Box(modifier = Modifier.fillMaxSize()) { MediaRouteButton(modifier = Modifier.align(Alignment.TopEnd)) PrimaryControls(player = player, modifier = Modifier.align(Alignment.Center)) } } } } @Composable fun PrimaryControls(player: Player, modifier: Modifier = Modifier) { ... }
將 MediaRouteButton 新增至 PlayerView
你可以在 PlayerView 的 UI 控制項中直接新增 MediaRouteButton。將 MediaController 設為 PlayerView 的播放器後,請提供 MediaRouteButtonViewProvider,在播放器上顯示 Cast 按鈕。
Kotlin
override fun onStart() { super.onStart() playerView.player = mediaController playerView.setMediaRouteButtonViewProvider(MediaRouteButtonViewProvider()) }
Java
@Override public void onStart() { super.onStart(); playerView.setPlayer(mediaController); playerView.setMediaRouteButtonViewProvider(new MediaRouteButtonViewProvider()); }
在應用程式列選單中新增 MediaRouteButton
如要在應用程式列選單中設定 MediaRouteButton,請建立 XML 選單,並覆寫 Activity 中的 onCreateOptionsMenu。
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:showAsAction="always"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"/>
</menu>
Kotlin
override fun onCreateOptionsMenu(menu: Menu): Boolean { ... menuInflater.inflate(R.menu.sample_media_route_button_menu, menu) val menuItemFuture: ListenableFuture<MenuItem> = MediaRouteButtonFactory.setUpMediaRouteButton( context, menu, R.id.media_route_menu_item) Futures.addCallback( menuItemFuture, object : FutureCallback<MenuItem> { override fun onSuccess(menuItem: MenuItem?) { // Do something with the menu item. } override fun onFailure(t: Throwable) { // Handle the failure. } }, executor) ... }
Java
@Override public boolean onCreateOptionsMenu(Menu menu) { ... getMenuInflater().inflate(R.menu.sample_media_route_button_menu, menu); ListenableFuture<MenuItem> menuItemFuture = MediaRouteButtonFactory.setUpMediaRouteButton( context, menu, R.id.media_route_menu_item); Futures.addCallback( menuItemFuture, new FutureCallback<MenuItem>() { @Override public void onSuccess(MenuItem menuItem) { // Do something with the menu item. } @Override public void onFailure(Throwable t) { // Handle the failure. } }, executor); ... }
將 MediaRouteButton 新增為檢視畫面
您可以在活動 layout.xml 中設定 MediaRouteButton。
<androidx.mediarouter.app.MediaRouteButton
android:id="@+id/media_route_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:mediaRouteButtonTint="@android:color/white" />
如要完成 MediaRouteButton 的設定,請在 Activity 程式碼中使用 Media3 Cast MediaRouteButtonFactory。
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) findViewById<MediaRouteButton>(R.id.media_route_button)?.also { val unused = MediaRouteButtonFactory.setUpMediaRouteButton(context, it) } }
Java
@Override public void onCreate(Bundle savedInstanceState) { ... MediaRouteButton button = findViewById(R.id.media_route_button); ListenableFuture<Void> setUpFuture = MediaRouteButtonFactory.setUpMediaRouteButton(context, button); }
活動監聽器
在 Activity 中建立 Player.Listener,監聽媒體播放位置的變更。當 playbackType 在 PLAYBACK_TYPE_LOCAL 和 PLAYBACK_TYPE_REMOTE 之間變更時,您可以視需要調整 UI。為避免記憶體流失,並將監聽器活動限制在應用程式顯示時,請在 onStart 中註冊監聽器,並在 onStop 中取消註冊:
Kotlin
import androidx.media3.common.DeviceInfo import androidx.media3.common.Player private val playerListener: Player.Listener = object : Player.Listener { override fun onDeviceInfoChanged(deviceInfo: DeviceInfo) { if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) { // Add UI changes for local playback. } else if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_REMOTE) { // Add UI changes for remote playback. } } } override fun onStart() { super.onStart() mediaController.addListener(playerListener) } override fun onStop() { super.onStop() mediaController.removeListener(playerListener) }
Java
import androidx.media3.common.DeviceInfo; import androidx.media3.common.Player; private Player.Listener playerListener = new Player.Listener() { @Override public void onDeviceInfoChanged(DeviceInfo deviceInfo) { if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_LOCAL) { // Add UI changes for local playback. } else if (deviceInfo.playbackType == DeviceInfo.PLAYBACK_TYPE_REMOTE) { // Add UI changes for remote playback. } } }; @Override protected void onStart() { super.onStart(); mediaController.addListener(playerListener); } @Override protected void onStop() { super.onStop(); mediaController.removeListener(playerListener); }
如要進一步瞭解如何監聽及回應播放事件,請參閱播放器事件指南。