Pierwsze kroki z CastPlayer

CastPlayer to implementacja odtwarzacza Jetpack Media3, która obsługuje zarówno odtwarzanie lokalne, jak i przesyłanie na zdalne urządzenie obsługujące Cast. CastPlayer ułatwia dodawanie do aplikacji funkcji przesyłania i zapewnia bogate funkcje, które umożliwiają płynne przełączanie się między odtwarzaniem lokalnym i zdalnym. Z tego przewodnika dowiesz się, jak zintegrować CastPlayer z aplikacją multimedialną.

Aby zintegrować Cast z innymi platformami, zapoznaj się z pakietem Cast SDK.

Kup urządzenie obsługujące Cast

Aby przetestować CastPlayer, musisz mieć urządzenie obsługujące Cast. Możesz wybrać urządzenia z Androidem TV, Chromecasta, inteligentne głośniki i inteligentne ekrany. Sprawdź, czy urządzenie jest skonfigurowane i połączone z tą samą siecią Wi-Fi co urządzenie mobilne, na którym prowadzisz testy.

Dodawanie zależności kompilacji

Aby zacząć korzystać z CastPlayer, dodaj zależności AndroidX Media3 i CastPlayer do pliku build.gradle modułu aplikacji.

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"

Konfigurowanie CastPlayer

Aby skonfigurować CastPlayer, zaktualizuj plik AndroidManifest.xml, dodając dostawcę opcji.

Dostawca opcji

Element CastPlayer wymaga skonfigurowania jego działania przez dostawcę opcji. W przypadku konfiguracji podstawowej możesz użyć DefaultCastOptionsProvider, dodając go do pliku AndroidManifest.xml. Spowoduje to użycie ustawień domyślnych, w tym domyślnej aplikacji odbiornika.

<application>
  ...
  <meta-data
    android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
    android:value="androidx.media3.cast.DefaultCastOptionsProvider" />
  ...
</application>

Aby dostosować konfigurację, zaimplementuj własny element OptionsProvider. Więcej informacji znajdziesz w przewodniku CastOptions.

Dodawanie odbiorcy do przesyłania multimediów

Dodanie elementu MediaTransferReceiver do pliku manifestu umożliwia interfejsowi systemu wykrywanie w sieci urządzeń obsługujących Cast i przekierowywanie multimediów bez otwierania aktywności aplikacji. Użytkownik może na przykład zmienić urządzenie, na którym odtwarzane są multimedia z Twojej aplikacji, za pomocą powiadomienia o multimediach.

<application>
  ...
  <receiver android:name="androidx.mediarouter.media.MediaTransferReceiver" />
  ...
</application>

Tworzenie odtwarzacza CastPlayer

W przypadku odtwarzania zdalnego za pomocą Cast aplikacja powinna zarządzać odtwarzaniem nawet wtedy, gdy użytkownik nie wchodzi w interakcję z aktywnością w aplikacji, np. za pomocą systemowego powiadomienia o multimediach. Z tego powodu instancje ExoPlayer (do odtwarzania lokalnego) i CastPlayer (do odtwarzania zdalnego) należy tworzyć w usłudze, np. MediaSessionService lub MediaLibraryService. Najpierw utwórz instancję ExoPlayer, a potem podczas tworzenia instancji CastPlayer ustaw ExoPlayer jako instancję lokalnego odtwarzacza. Możesz wtedy przełączać odtwarzanie multimediów między urządzeniem mobilnym a urządzeniem obsługującym Cast z poziomu powiadomienia o multimediach lub powiadomienia na ekranie blokady. Media3 korzysta z funkcji OutputSwitcher, aby obsługiwać przenoszenie odtwarzacza, gdy trasa wyjściowa zmienia się z lokalnej na zdalną lub ze zdalnej na lokalną.

Zrzut ekranu przedstawiający interfejs przełącznika wyjścia w powiadomieniach.
Ilustracja 1. (a) Karta urządzenia w powiadomieniu o multimediach. (b) Urządzenia obsługujące przesyłanie, które pojawiają się po kliknięciu karty urządzenia. (c) Karta urządzenia w powiadomieniu na ekranie blokady.

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();
}

Dodawanie elementów interfejsu

Dodaj MediaRouteButton do interfejsu aplikacji. Kliknięcie MediaRouteButton otwiera okno z listą dostępnych urządzeń obsługujących Cast w sieci. Gdy użytkownik wybierze urządzenie, odtwarzanie multimediów zostanie przeniesione z telefonu na wybrane urządzenie odbiorcze. W tej sekcji dowiesz się, jak dodać przycisk i nasłuchiwać zdarzeń, aby aktualizować interfejs, gdy odtwarzanie przełącza się między urządzeniami lokalnymi i zdalnymi.

Ustawianie elementu MediaRouteButton

Istnieją 4 sposoby dodania elementu MediaRouteButton do interfejsu aktywności. Najlepszy wybór zależy od projektu i wymagań aplikacji.

  • Compose UI: dodaj funkcję kompozycyjną przycisku.
  • Interfejs wyświetleń:
    • Dodaj przycisk do menu paska aplikacji.
    • Dodaj przycisk w tagu PlayerView.
    • Dodaj przycisk jako standardowy View.
Zrzut ekranu przedstawiający przycisk MediaRouteButton w interfejsie.
Ilustracja 2. (a) Przycisk MediaRouteButton na pasku menu, (b) jako widok, (c) w widoku odtwarzacza i (d) okno dialogowe urządzeń obsługujących Cast.

Dodawanie komponentu MediaRouteButton do odtwarzacza

Możesz dodać komponent MediaRouteButton do interfejsu odtwarzacza. Więcej informacji znajdziesz w przewodniku Compose.

@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) {
  // ...
}

Dodaj MediaRouteButton do PlayerView

Możesz dodać MediaRouteButton bezpośrednio w elementach interfejsu PlayerView. Po ustawieniu MediaController jako odtwarzacza dla elementu PlayerView podaj element MediaRouteButtonViewProvider, aby wyświetlić przycisk przesyłania na odtwarzaczu.

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());
}

Dodawanie ikony MediaRouteButton do menu paska aplikacji

Aby skonfigurować MediaRouteButton w menu paska aplikacji, utwórz menu XML i zastąp onCreateOptionsMenuActivity.

<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,
  )
  // ...
  return true
}

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);
  // ...
  return true;
}

Dodaj MediaRouteButton jako widok

Możesz skonfigurować MediaRouteButton w pliku układu aktywności layout.xml.

  <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" />

Aby dokończyć konfigurację MediaRouteButton, użyj w kodzie Activity interfejsu Media3 CastMediaRouteButtonFactory.

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) {
  super.onCreate(savedInstanceState);
  // ...
  MediaRouteButton button = findViewById(R.id.media_route_button);
  ListenableFuture<Void> setUpFuture =
      MediaRouteButtonFactory.setUpMediaRouteButton(context, button);
}

Detektor aktywności

Utwórz Player.ListenerActivity, aby nasłuchiwać zmian lokalizacji odtwarzania multimediów. Gdy playbackType zmieni się z PLAYBACK_TYPE_LOCAL na PLAYBACK_TYPE_REMOTE, możesz dostosować interfejs do swoich potrzeb. Aby zapobiec wyciekom pamięci i ograniczyć aktywność odbiornika tylko do momentu, gdy aplikacja jest widoczna, zarejestruj odbiornik w funkcji onStart i wyrejestruj go w funkcji onStop:

Kotlin

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

private final 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);
}

Więcej informacji o nasłuchiwaniu zdarzeń odtwarzania i reagowaniu na nie znajdziesz w przewodniku Zdarzenia odtwarzacza.