תחילת העבודה עם CastPlayer

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.0-alpha01")
implementation("androidx.media3:media3-ui:1.9.0-alpha01")
implementation("androidx.media3:media3-session:1.9.0-alpha01")
implementation("androidx.media3:media3-cast:1.9.0-alpha01")

Groovy

implementation "androidx.media3:media3-exoplayer:1.9.0-alpha01"
implementation "androidx.media3:media3-ui:1.9.0-alpha01"
implementation "androidx.media3:media3-session:1.9.0-alpha01"
implementation "androidx.media3:media3-cast:1.9.0-alpha01"

כדי לשלב את CastPlayer באפליקציה, צריך לעיין בהערות לגבי הגרסה של Jetpack Media ולמצוא את גרסת האלפא האחרונה. כל המודולים צריכים להיות באותה גרסה.

מידע נוסף על מודולי הספרייה הזמינים מופיע בדף Google Maven AndroidX Media3.

הגדרת 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 לממשק המשתמש של הפעילות, כדי שהמשתמשים יוכלו לקיים איתו אינטראקציה. הבחירה תלויה במראה ובאופן הפעולה הרצויים של ממשק המשתמש של פעילות הנגן.

הוספת כפתור של מסלול מדיה שניתן להגדרה לנגן

אפשר להוסיף את רכיב ה-MediaRouteButton ל-UI של הנגן. מידע נוסף זמין במדריך בנושא כתיבת הודעות.

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 CastMediaRouteButtonFactory בקוד 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);
}

מידע נוסף על האזנה לאירועי הפעלה ותגובה להם זמין במדריך בנושא אירועים של נגן.