CastPlayer הוא הטמעה של Player ב-Jetpack Media3 שתומכת בהפעלה מקומית וגם בהעברה למכשיר מרוחק שתומך ב-Cast. CastPlayer
הספרייה מפשטת את הוספת הפונקציונליות של Cast לאפליקציה ומספקת תכונות עשירות למעבר חלק בין הפעלה מקומית להפעלה מרחוק. במדריך הזה נסביר איך לשלב את CastPlayer באפליקציית המדיה שלכם.
כדי לשלב את Cast עם פלטפורמות אחרות, אפשר לעיין ב-Cast SDK.
הוספת CastPlayer כתלות
כדי להתחיל להשתמש ב-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, צריך ספק אפשרויות. כדי לבצע הגדרה בסיסית, אפשר להשתמש באפשרויות ברירת המחדל שסופקו על ידי הוספה שלהן לקובץ 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 למניפסט מאפשרת לממשק המשתמש של המערכת לנתב מחדש מדיה בלי לפתוח את פעילות האפליקציה. לדוגמה, משתמש יכול לשנות את המכשיר שמפעיל את המדיה של האפליקציה שלכם מההתראה על המדיה.
<application>
<receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />
</application>
יצירת CastPlayer
כדי להפעיל השמעה מרחוק באמצעות Cast, האפליקציה צריכה לנהל את ההשמעה גם כשהמשתמש לא מקיים אינטראקציה עם פעילות מהאפליקציה, למשל באמצעות ההתראה על מדיה במערכת. לכן, כדאי ליצור את המופעים של ExoPlayer (להפעלה מקומית) ושל CastPlayer בשירות, כמו MediaSessionService או MediaLibraryService. קודם יוצרים מופע של ExoPlayer, ואז כשיוצרים מופע של CastPlayer, מגדירים את ExoPlayer כמופע של נגן מקומי. לאחר מכן, 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(); }
הוספת רכיבים בממשק המשתמש
מוסיפים MediaRouteButton לממשק המשתמש של האפליקציה כדי לאפשר למשתמשים לבחור מכשיר Cast.
בסעיף הזה מוסבר איך להוסיף את הלחצן ולהאזין לאירועים כדי לעדכן את ממשק המשתמש כשמעבירים את ההפעלה בין מכשירים מקומיים ומרוחקים.
הגדרת MediaRouteButton
יש ארבע שיטות אפשריות להוספת MediaRouteButton לממשק המשתמש של הפעילות כדי שהמשתמשים יוכלו לבצע איתו אינטראקציה. הבחירה תלויה במראה ובאופן הפעולה הרצויים של ממשק המשתמש של פעילות הנגן.
הוספת כפתור של מסלול מדיה שניתן להגדרה לנגן
אפשר להוסיף את רכיב ה-Composable MediaRouteButton לממשק המשתמש של הנגן. מידע נוסף זמין במדריך בנושא כתיבת הודעות.
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) { ... }
הוספת הכפתור של נתיב המדיה ל-PlayerView
אפשר להוסיף את MediaRouteButton ישירות בתוך אמצעי הבקרה של ממשק המשתמש של PlayerView. אחרי שמגדירים את 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()); }
הוספת כפתור של נתיב מדיה לתפריט של סרגל האפליקציות
בשיטה הזו מוגדר לחצן של מסלול מדיה בתפריט של סרגל האפליקציות. כדי להציג את הסגנון הזה של לחצן, צריך לעדכן את קובץ המניפסט ואת Activity.
<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, משתמשים ב-Media3
Cast MediaRouteButtonFactory בקוד Activity.
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 Listener
יוצרים Player.Listener ב-Activity כדי להאזין לשינויים במיקום ההפעלה של המדיה. כשערך המשתנה playbackType משתנה בין PLAYBACK_TYPE_LOCAL
לבין PLAYBACK_TYPE_REMOTE, אפשר לשנות את ממשק המשתמש לפי הצורך. כדי למנוע דליפות זיכרון וכדי להגביל את פעילות המאזין רק למקרים שבהם האפליקציה גלויה, צריך לרשום את המאזין ב-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); }
מידע נוסף על האזנה לאירועי הפעלה ועל תגובה להם זמין במדריך בנושא אירועים של נגן.