Obsługa przesyłania w aplikacji na Androida

1. Przegląd

Logo Google Cast

Z tego samouczka dowiesz się, jak zmodyfikować istniejącą aplikację do odtwarzania filmów na Androida, aby przesyłać treści na urządzenie obsługujące Google Cast.

Co to jest Google Cast?

Google Cast umożliwia przesyłanie treści z urządzenia mobilnego na telewizor. Użytkownicy mogą wtedy używać urządzenia mobilnego jako pilota do odtwarzania multimediów na telewizorze.

Pakiet Google Cast SDK umożliwia rozszerzenie aplikacji o możliwość sterowania telewizorem lub systemem dźwiękowym. Pakiet Cast SDK umożliwia dodawanie niezbędnych komponentów interfejsu na podstawie listy kontrolnej projektu Google Cast.

Lista kontrolna projektu Google Cast została opracowana, aby zapewnić prostotę i przewidywalność korzystania z Cast na wszystkich obsługiwanych platformach.

Co będziemy tworzyć?

Po ukończeniu tego kursu będziesz mieć aplikację na Androida do odtwarzania filmów, która będzie mogła przesyłać filmy na urządzenie obsługujące Google Cast.

Czego się nauczysz

  • Jak dodać pakiet Google Cast SDK do przykładowej aplikacji wideo.
  • Jak dodać przycisk Cast, aby wybrać urządzenie przesyłające.
  • Jak połączyć się z urządzeniem przesyłającym i uruchomić odbiornik multimediów.
  • Jak przesyłać filmy
  • Jak dodać do aplikacji minikontroler Cast.
  • Jak obsługiwać powiadomienia o multimediach i sterowanie na ekranie blokady.
  • Jak dodać rozszerzony kontroler
  • Jak wyświetlić nakładkę wprowadzającą
  • Jak dostosować widżety Cast
  • Integracja z Cast Connect

Czego potrzebujesz

  • Najnowszy Android SDK.
  • Android Studio w wersji 3.2 lub nowszej
  • Urządzenie mobilne z Androidem 4.1 lub nowszym (Jelly Bean, poziom interfejsu API 16).
  • kabel USB do przesyłania danych, który umożliwia połączenie urządzenia mobilnego z komputerem deweloperskim;
  • Urządzenie przesyłające, np. Chromecast lub Android TV, skonfigurowane z dostępem do internetu.
  • telewizor lub monitor z wejściem HDMI,
  • Do przetestowania integracji Cast Connect wymagany jest Chromecast z Google TV, ale w pozostałej części Codelabu jest on opcjonalny. Jeśli nie masz takiego urządzenia, możesz pominąć krok Dodawanie obsługi Cast Connect pod koniec tego samouczka.

Doświadczenie

  • Musisz mieć wcześniejszą wiedzę na temat programowania w języku Kotlin i tworzenia aplikacji na Androida.
  • Musisz też mieć doświadczenie w oglądaniu telewizji.

Jak zamierzasz korzystać z tego samouczka?

Tylko przeczytaj Przeczytaj i wykonaj ćwiczenia

Jak oceniasz swoje doświadczenie w tworzeniu aplikacji na Androida?

Początkujący Średnio zaawansowany Zaawansowany

Jak oceniasz oglądanie telewizji?

Początkujący Średnio zaawansowany Zaawansowany

2. Pobieranie przykładowego kodu

Możesz pobrać cały przykładowy kod na komputer…

i rozpakuj pobrany plik ZIP.

3. Uruchamianie przykładowej aplikacji

ikona cyrkla,

Najpierw zobaczmy, jak wygląda gotowa przykładowa aplikacja. Aplikacja jest podstawowym odtwarzaczem wideo. Użytkownik może wybrać film z listy, a następnie odtworzyć go lokalnie na urządzeniu lub przesłać na urządzenie przesyłające Google Cast.

Po pobraniu kodu wykonaj te instrukcje, aby otworzyć i uruchomić gotową przykładową aplikację w Android Studio:

Na ekranie powitalnym wybierz Importuj projekt lub kliknij Plik > Nowy > Importuj projekt….

Wybierz katalog ikona folderuapp-done z folderu z przykładowym kodem i kliknij OK.

Kliknij PlikPrzycisk „Sync Project with Gradle” (Synchronizuj projekt z Gradle) w Android Studio Synchronizuj projekt z plikami Gradle.

Włącz debugowanie USB na urządzeniu z Androidem – w Androidzie 4.2 i nowszym ekran Opcje programisty jest domyślnie ukryty. Aby go wyświetlić, otwórz Ustawienia > Informacje o telefonie i 7 razy kliknij Numer kompilacji. Wróć do poprzedniego ekranu, kliknij System > Zaawansowane i u dołu wybierz Opcje programisty, a następnie kliknij Debugowanie USB, aby włączyć tę opcję.

Podłącz urządzenie z Androidem i w Android Studio kliknij przycisk Przycisk Uruchom w Android Studio, zielony trójkąt skierowany w prawoUruchom. Po kilku sekundach powinna pojawić się aplikacja wideo o nazwie Przesyłaj filmy.

Kliknij przycisk Cast w aplikacji wideo i wybierz urządzenie przesyłające Google Cast.

Wybierz film i kliknij przycisk odtwarzania.

Film zacznie się odtwarzać na urządzeniu przesyłającym Google Cast.

Wyświetli się rozwinięty kontroler. Aby sterować odtwarzaniem, możesz użyć przycisku odtwarzania/wstrzymywania.

Wróć do listy filmów.

U dołu ekranu pojawi się minikontroler. Ilustracja przedstawiająca telefon z Androidem z aplikacją „Przesyłaj filmy” i 3 mini kontrolerami u dołu ekranu

Kliknij przycisk wstrzymania na minikontrolerze, aby wstrzymać film na odbiorniku. Kliknij przycisk odtwarzania na minikontrolerze, aby ponownie odtworzyć film.

Kliknij przycisk ekranu głównego na urządzeniu mobilnym. Pociągnij w dół powiadomienia. Powinno pojawić się powiadomienie o sesji przesyłania.

Zablokuj telefon, a gdy go odblokujesz, na ekranie blokady powinno pojawić się powiadomienie umożliwiające sterowanie odtwarzaniem multimediów lub zatrzymanie przesyłania.

Wróć do aplikacji wideo i kliknij przycisk Cast, aby zatrzymać przesyłanie na urządzenie przesyłające Google Cast.

Najczęstsze pytania

4. Przygotowywanie projektu początkowego

Ilustracja przedstawiająca telefon z Androidem z aplikacją „Przesyłaj filmy”

Musimy dodać obsługę Google Cast do pobranej aplikacji startowej. Oto niektóre terminy związane z Google Cast, których będziemy używać w tym ćwiczeniu:

  • aplikacja nadawcy jest uruchomiona na urządzeniu mobilnym lub laptopie,
  • na urządzeniu przesyłającym działa aplikacja odbiornika;

Możesz teraz rozbudowywać projekt początkowy za pomocą Androida Studio:

  1. Wybierz katalog ikona folderuapp-start z pobranego kodu przykładowego (na ekranie powitalnym kliknij Import Project lub wybierz opcję menu File > New > Import Project...).
  2. Kliknij przycisk Przycisk „Sync Project with Gradle” (Synchronizuj projekt z Gradle) w Android Studio Synchronizuj projekt z plikami Gradle.
  3. Aby uruchomić aplikację i zapoznać się z interfejsem, kliknij przycisk Przycisk Uruchom w Android Studio, zielony trójkąt skierowany w prawoUruchom.

Projektowanie aplikacji

Aplikacja pobiera listę filmów z zdalnego serwera internetowego i udostępnia ją użytkownikowi. Użytkownicy mogą wybrać film, aby wyświetlić szczegóły lub odtworzyć go lokalnie na urządzeniu mobilnym.

Aplikacja składa się z 2 głównych działań: VideoBrowserActivityLocalPlayerActivity. Aby zintegrować funkcję Google Cast, aktywności muszą dziedziczyć po klasie AppCompatActivity lub jej klasie nadrzędnej FragmentActivity. To ograniczenie wynika z tego, że musimy dodać MediaRouteButton (dostępny w bibliotece pomocy MediaRouter) jako MediaRouteActionProvider, a to będzie działać tylko wtedy, gdy aktywność będzie dziedziczyć po wspomnianych wyżej klasach. Biblioteka pomocy MediaRouter zależy od biblioteki pomocy AppCompat, która udostępnia wymagane klasy.

VideoBrowserActivity

Ta aktywność zawiera Fragment (VideoBrowserFragment). Ta lista jest obsługiwana przez ArrayAdapter (VideoListAdapter). Lista filmów i powiązanych z nimi metadanych jest hostowana na serwerze zdalnym jako plik JSON. AsyncTaskLoader (VideoItemLoader) pobiera ten plik JSON i przetwarza go, aby utworzyć listę obiektów MediaItem.

Obiekt MediaItem modeluje film i powiązane z nim metadane, takie jak tytuł, opis, adres URL strumienia, adres URL obrazów pomocniczych i powiązane ścieżki tekstowe (napisy), jeśli takie istnieją. Obiekt MediaItem jest przekazywany między aktywnościami, więc MediaItem ma metody narzędziowe do konwertowania go na obiekt Bundle i odwrotnie.

Gdy moduł wczytujący utworzy listę MediaItems, przekazuje ją do VideoListAdapter, który następnie wyświetla listę MediaItemsVideoBrowserFragment. Użytkownikowi wyświetla się lista miniatur filmów z krótkim opisem każdego z nich. Gdy element zostanie wybrany, odpowiadający mu znak MediaItem zostanie przekształcony w znak Bundle i przekazany do elementu LocalPlayerActivity.

LocalPlayerActivity

Ta aktywność wyświetla metadane dotyczące konkretnego filmu i umożliwia użytkownikowi odtworzenie go lokalnie na urządzeniu mobilnym.

Aktywność zawiera VideoView, niektóre opcje sterowania multimediami i obszar tekstowy, w którym wyświetla się opis wybranego filmu. Odtwarzacz zajmuje górną część ekranu, a pod nim znajduje się miejsce na szczegółowy opis filmu. Użytkownik może odtwarzać i wstrzymywać filmy oraz przewijać je lokalnie.

Zależności

Ponieważ używamy AppCompatActivity, potrzebujemy biblioteki pomocy AppCompat. Do zarządzania listą filmów i asynchronicznego pobierania obrazów z listy używamy biblioteki Volley.

Najczęstsze pytania

5. Dodawanie przycisku Cast

Ilustracja przedstawiająca górną część telefonu z Androidem z uruchomioną aplikacją Przesyłaj wideo. Przycisk przesyłania jest widoczny w prawym górnym rogu ekranu.

Aplikacja obsługująca Cast wyświetla przycisk Cast w każdej aktywności. Kliknięcie przycisku Cast powoduje wyświetlenie listy urządzeń obsługujących Cast, z której użytkownik może wybrać urządzenie. Jeśli użytkownik odtwarzał treści lokalnie na urządzeniu wysyłającym, wybranie urządzenia przesyłającego spowoduje rozpoczęcie lub wznowienie odtwarzania na tym urządzeniu. W dowolnym momencie sesji Cast użytkownik może kliknąć przycisk Cast i zatrzymać przesyłanie aplikacji na urządzenie przesyłające. Użytkownik musi mieć możliwość połączenia się z urządzeniem przesyłającym lub odłączenia się od niego podczas korzystania z dowolnej funkcji aplikacji, zgodnie z opisem w liście kontrolnej projektu Google Cast.

Zależności

Zaktualizuj plik build.gradle aplikacji, aby uwzględnić niezbędne zależności bibliotek:

dependencies {
    implementation 'androidx.appcompat:appcompat:1.5.0'
    implementation 'androidx.mediarouter:mediarouter:1.3.1'
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    implementation 'com.google.android.gms:play-services-cast-framework:21.1.0'
    implementation 'com.android.volley:volley:1.2.1'
    implementation "androidx.core:core-ktx:1.8.0"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}

Zsynchronizuj projekt, aby sprawdzić, czy kompilacja przebiega bez błędów.

Zdarzenie inicjujące

Platforma Cast ma globalny obiekt singleton CastContext, który koordynuje wszystkie interakcje Cast.

Aby dostarczyć CastOptions potrzebne do zainicjowania singletonu CastContext, musisz zaimplementować interfejs OptionsProvider. Najważniejsza opcja to identyfikator aplikacji odbiornika, który służy do filtrowania wyników wykrywania urządzeń przesyłających i uruchamiania aplikacji odbiornika po rozpoczęciu sesji Cast.

Podczas tworzenia własnej aplikacji obsługującej Cast musisz zarejestrować się jako deweloper Cast, a następnie uzyskać identyfikator aplikacji. W tym samouczku użyjemy przykładowego identyfikatora aplikacji.

Dodaj do pakietu com.google.sample.cast.refplayer projektu ten nowy plik CastOptionsProvider.kt:

package com.google.sample.cast.refplayer

import android.content.Context
import com.google.android.gms.cast.framework.OptionsProvider
import com.google.android.gms.cast.framework.CastOptions
import com.google.android.gms.cast.framework.SessionProvider

class CastOptionsProvider : OptionsProvider {
    override fun getCastOptions(context: Context): CastOptions {
        return CastOptions.Builder()
                .setReceiverApplicationId(context.getString(R.string.app_id))
                .build()
    }

    override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
        return null
    }
}

Teraz zadeklaruj OptionsProvider w tagu „application” w pliku AndroidManifest.xml aplikacji:

<meta-data
    android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
    android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />

Zainicjuj CastContext w metodzie VideoBrowserActivity onCreate:

import com.google.android.gms.cast.framework.CastContext

private var mCastContext: CastContext? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.video_browser)
    setupActionBar()

    mCastContext = CastContext.getSharedInstance(this)
}

Dodaj tę samą logikę inicjowania do elementu LocalPlayerActivity.

Przycisk Cast

Gdy CastContext zostanie zainicjowany, musimy dodać przycisk Cast, aby umożliwić użytkownikowi wybór urządzenia przesyłającego. Przycisk Cast jest implementowany przez funkcję MediaRouteButton z biblioteki pomocy MediaRouter. Podobnie jak w przypadku każdej ikony działania, którą możesz dodać do aktywności (za pomocą ikony ActionBar lub Toolbar), najpierw musisz dodać odpowiedni element menu do menu.

Edytuj plik res/menu/browse.xml i dodaj element MediaRouteActionProvider w menu przed elementem ustawień:

<item
    android:id="@+id/media_route_menu_item"
    android:title="@string/media_route_menu_title"
    app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
    app:showAsAction="always"/>

Zastąp metodę onCreateOptionsMenu() klasy VideoBrowserActivity, używając CastButtonFactory, aby połączyć MediaRouteButton z platformą Cast:

import com.google.android.gms.cast.framework.CastButtonFactory

private var mediaRouteMenuItem: MenuItem? = null

override fun onCreateOptionsMenu(menu: Menu): Boolean {
     super.onCreateOptionsMenu(menu)
     menuInflater.inflate(R.menu.browse, menu)
     mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu,
                R.id.media_route_menu_item)
     return true
}

Zastąp onCreateOptionsMenuLocalPlayerActivity w podobny sposób.

Kliknij przycisk Przycisk Uruchom w Android Studio, zielony trójkąt skierowany w prawoUruchom, aby uruchomić aplikację na urządzeniu mobilnym. W pasku działań aplikacji powinien pojawić się przycisk Cast. Po kliknięciu go wyświetli się lista urządzeń przesyłających w Twojej sieci lokalnej. Wykrywanie urządzeń jest zarządzane automatycznie przez CastContext. Wybierz urządzenie przesyłające, a na nim wczyta się przykładowa aplikacja odbiornika. Możesz przełączać się między aktywnością przeglądania a aktywnością lokalnego odtwarzacza, a stan przycisku Cast będzie synchronizowany.

Nie obsługujemy jeszcze odtwarzania multimediów, więc nie możesz jeszcze odtwarzać filmów na urządzeniu przesyłającym. Aby odłączyć urządzenie, kliknij przycisk Cast.

6. Przesyłanie treści wideo

Ilustracja przedstawiająca telefon z Androidem z aplikacją „Przesyłaj filmy”

Rozszerzymy przykładową aplikację, aby można było odtwarzać filmy zdalnie na urządzeniu przesyłającym. Aby to zrobić, musimy nasłuchiwać różnych zdarzeń generowanych przez platformę Cast.

Przesyłanie multimediów

Jeśli chcesz odtworzyć multimedia na urządzeniu przesyłającym, musisz wykonać te czynności:

  1. Utwórz obiekt MediaInfo, który modeluje element multimedialny.
  2. Połącz się z urządzeniem przesyłającym i uruchom aplikację odbiornika.
  3. Włóż MediaInfo do odbiornika i odtwórz treści.
  4. śledzić stan multimediów,
  5. Wysyłanie poleceń odtwarzania do odbiornika na podstawie interakcji użytkownika.

Krok 2 został już wykonany w poprzedniej sekcji. Krok 3 jest łatwy do wykonania za pomocą platformy Cast. Krok 1 polega na mapowaniu jednego obiektu na inny. MediaInfo to element, który jest zrozumiały dla platformy Cast, a MediaItem to hermetyzacja elementu multimedialnego w naszej aplikacji. Możemy łatwo zmapować MediaItem na MediaInfo.

Przykładowa aplikacja LocalPlayerActivity rozróżnia już odtwarzanie lokalne i zdalne za pomocą tego wyliczenia:

private var mLocation: PlaybackLocation? = null

enum class PlaybackLocation {
    LOCAL, REMOTE
}

enum class PlaybackState {
    PLAYING, PAUSED, BUFFERING, IDLE
}

W tym ćwiczeniu nie musisz dokładnie rozumieć, jak działa cała logika przykładowego odtwarzacza. Pamiętaj, że odtwarzacz multimediów w Twojej aplikacji będzie musiał zostać zmodyfikowany, aby w podobny sposób rozpoznawać 2 lokalizacje odtwarzania.

Obecnie odtwarzacz lokalny jest zawsze w stanie odtwarzania lokalnego, ponieważ nie ma jeszcze informacji o stanach przesyłania. Musimy zaktualizować interfejs na podstawie przejść stanu, które występują w platformie Cast. Jeśli na przykład rozpoczniemy przesyłanie, musimy zatrzymać lokalne odtwarzanie i wyłączyć niektóre elementy sterujące. Podobnie, jeśli zatrzymamy przesyłanie podczas tej aktywności, musimy przejść na odtwarzanie lokalne. Aby to zrobić, musimy nasłuchiwać różnych zdarzeń generowanych przez platformę Cast.

Zarządzanie sesją przesyłania

W przypadku platformy Cast sesja Cast łączy w sobie czynności związane z łączeniem się z urządzeniem, uruchamianiem (lub dołączaniem), łączeniem się z aplikacją odbiornika i inicjowaniem kanału sterowania multimediami (w razie potrzeby). Kanał sterowania multimediami służy do wysyłania i odbierania wiadomości z odtwarzacza multimediów odbiornika.

Sesja Cast rozpocznie się automatycznie, gdy użytkownik wybierze urządzenie za pomocą przycisku Cast, i zakończy się automatycznie, gdy użytkownik się rozłączy. Ponowne łączenie z sesją odbiornika z powodu problemów z siecią jest również obsługiwane automatycznie przez pakiet Cast SDK.

Dodajmy SessionManagerListener do LocalPlayerActivity:

import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
...

private var mSessionManagerListener: SessionManagerListener<CastSession>? = null
private var mCastSession: CastSession? = null
...

private fun setupCastListener() {
    mSessionManagerListener = object : SessionManagerListener<CastSession> {
        override fun onSessionEnded(session: CastSession, error: Int) {
            onApplicationDisconnected()
        }

        override fun onSessionResumed(session: CastSession, wasSuspended: Boolean) {
            onApplicationConnected(session)
        }

        override fun onSessionResumeFailed(session: CastSession, error: Int) {
            onApplicationDisconnected()
        }

        override fun onSessionStarted(session: CastSession, sessionId: String) {
            onApplicationConnected(session)
        }

        override fun onSessionStartFailed(session: CastSession, error: Int) {
            onApplicationDisconnected()
        }

        override fun onSessionStarting(session: CastSession) {}
        override fun onSessionEnding(session: CastSession) {}
        override fun onSessionResuming(session: CastSession, sessionId: String) {}
        override fun onSessionSuspended(session: CastSession, reason: Int) {}
        private fun onApplicationConnected(castSession: CastSession) {
            mCastSession = castSession
            if (null != mSelectedMedia) {
                if (mPlaybackState == PlaybackState.PLAYING) {
                    mVideoView!!.pause()
                    loadRemoteMedia(mSeekbar!!.progress, true)
                    return
                } else {
                    mPlaybackState = PlaybackState.IDLE
                    updatePlaybackLocation(PlaybackLocation.REMOTE)
                }
            }
            updatePlayButton(mPlaybackState)
            invalidateOptionsMenu()
        }

        private fun onApplicationDisconnected() {
            updatePlaybackLocation(PlaybackLocation.LOCAL)
            mPlaybackState = PlaybackState.IDLE
            mLocation = PlaybackLocation.LOCAL
            updatePlayButton(mPlaybackState)
            invalidateOptionsMenu()
       }
   }
}

W LocalPlayerActivityaktywnościLocalPlayerActivity chcemy otrzymywać powiadomienia o połączeniu lub rozłączeniu z urządzeniem przesyłającym, aby móc przełączać się na odtwarzacz lokalny lub z niego. Pamiętaj, że połączenie może zostać przerwane nie tylko przez instancję aplikacji działającą na urządzeniu mobilnym, ale też przez inną instancję Twojej aplikacji (lub innej aplikacji) działającą na innym urządzeniu mobilnym.

Obecnie aktywna sesja jest dostępna jako SessionManager.getCurrentSession(). Sesje są tworzone i zamykane automatycznie w odpowiedzi na interakcje użytkownika z oknami przesyłania.

Musimy zarejestrować detektor sesji i zainicjować zmienne, których będziemy używać w aktywności. Zmień metodę LocalPlayerActivity onCreate na:

import com.google.android.gms.cast.framework.CastContext
...

private var mCastContext: CastContext? = null
...

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    mCastContext = CastContext.getSharedInstance(this)
    mCastSession = mCastContext!!.sessionManager.currentCastSession
    setupCastListener()
    ...
    loadViews()
    ...
    val bundle = intent.extras
    if (bundle != null) {
        ....
        if (shouldStartPlayback) {
              ....

        } else {
            if (mCastSession != null && mCastSession!!.isConnected()) {
                updatePlaybackLocation(PlaybackLocation.REMOTE)
            } else {
                updatePlaybackLocation(PlaybackLocation.LOCAL)
            }
            mPlaybackState = PlaybackState.IDLE
            updatePlayButton(mPlaybackState)
        }
    }
    ...
}

Wczytuję multimedia

W pakiecie Cast SDK klasa RemoteMediaClient udostępnia zestaw wygodnych interfejsów API do zarządzania zdalnym odtwarzaniem multimediów na odbiorniku. W przypadku CastSession obsługującego odtwarzanie multimediów pakiet SDK automatycznie utworzy instancję RemoteMediaClient. Dostęp do niego można uzyskać, wywołując metodę getRemoteMediaClient() na instancji CastSession. Dodaj te metody do LocalPlayerActivity, aby wczytać aktualnie wybrany film na odbiorniku:

import com.google.android.gms.cast.framework.media.RemoteMediaClient
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaLoadOptions
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.common.images.WebImage
import com.google.android.gms.cast.MediaLoadRequestData

private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
    if (mCastSession == null) {
        return
    }
    val remoteMediaClient = mCastSession!!.remoteMediaClient ?: return
    remoteMediaClient.load( MediaLoadRequestData.Builder()
                .setMediaInfo(buildMediaInfo())
                .setAutoplay(autoPlay)
                .setCurrentTime(position.toLong()).build())
}

private fun buildMediaInfo(): MediaInfo? {
    val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
    mSelectedMedia?.studio?.let { movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, it) }
    mSelectedMedia?.title?.let { movieMetadata.putString(MediaMetadata.KEY_TITLE, it) }
    movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(0))))
    movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(1))))
    return mSelectedMedia!!.url?.let {
        MediaInfo.Builder(it)
            .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
            .setContentType("videos/mp4")
            .setMetadata(movieMetadata)
            .setStreamDuration((mSelectedMedia!!.duration * 1000).toLong())
            .build()
    }
}

Teraz zaktualizuj różne istniejące metody, aby używać logiki sesji Cast do obsługi odtwarzania zdalnego:

private fun play(position: Int) {
    startControllersTimer()
    when (mLocation) {
        PlaybackLocation.LOCAL -> {
            mVideoView!!.seekTo(position)
            mVideoView!!.start()
        }
        PlaybackLocation.REMOTE -> {
            mPlaybackState = PlaybackState.BUFFERING
            updatePlayButton(mPlaybackState)
            //seek to a new position within the current media item's new position 
            //which is in milliseconds from the beginning of the stream
            mCastSession!!.remoteMediaClient?.seek(position.toLong())
        }
        else -> {}
    }
    restartTrickplayTimer()
}
private fun togglePlayback() {
    ...
    PlaybackState.IDLE -> when (mLocation) {
        ...
        PlaybackLocation.REMOTE -> {
            if (mCastSession != null && mCastSession!!.isConnected) {
                loadRemoteMedia(mSeekbar!!.progress, true)
            }
        }
        else -> {}
    }
    ...
}
override fun onPause() {
    ...
    mCastContext!!.sessionManager.removeSessionManagerListener(
                mSessionManagerListener!!, CastSession::class.java)
}
override fun onResume() {
    Log.d(TAG, "onResume() was called")
    mCastContext!!.sessionManager.addSessionManagerListener(
            mSessionManagerListener!!, CastSession::class.java)
    if (mCastSession != null && mCastSession!!.isConnected) {
        updatePlaybackLocation(PlaybackLocation.REMOTE)
    } else {
        updatePlaybackLocation(PlaybackLocation.LOCAL)
    }
    super.onResume()
}

W przypadku metody updatePlayButton zmień wartość zmiennej isConnected:

private fun updatePlayButton(state: PlaybackState?) {
    ...
    val isConnected = (mCastSession != null
                && (mCastSession!!.isConnected || mCastSession!!.isConnecting))
    ...
}

Teraz kliknij przycisk Przycisk Uruchom w Android Studio, zielony trójkąt skierowany w prawoUruchom, aby uruchomić aplikację na urządzeniu mobilnym. Połącz się z urządzeniem przesyłającym i zacznij odtwarzać film. Film powinien być odtwarzany na odbiorniku.

7. Mini kontroler

Lista kontrolna projektu Cast wymaga, aby wszystkie aplikacje Cast udostępniały mini kontroler, który pojawia się, gdy użytkownik opuści stronę z treścią. Miniodtwarzacz zapewnia natychmiastowy dostęp i widoczne przypomnienie o bieżącej sesji Cast.

Ilustracja przedstawiająca dolną część telefonu z Androidem z miniodtwarzaczem w aplikacji Przesyłaj filmy

Pakiet Cast SDK udostępnia niestandardowy widok MiniControllerFragment, który można dodać do pliku układu aplikacji w aktywnościach, w których chcesz wyświetlać miniodtwarzacz.

Dodaj tę definicję fragmentu na dole obu plików res/layout/player_activity.xmlres/layout/video_browser.xml:

<fragment
    android:id="@+id/castMiniController"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:visibility="gone"
    class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment"/>

Kliknij przycisk Przycisk Uruchom w Android Studio, zielony trójkąt skierowany w prawoUruchom, aby uruchomić aplikację i przesłać film. Gdy odtwarzanie rozpocznie się na odbiorniku, u dołu każdej aktywności powinien pojawić się minikontroler. Odtwarzaniem zdalnym możesz sterować za pomocą minikontrolera. Jeśli przełączasz się między aktywnością przeglądania a aktywnością lokalnego odtwarzacza, stan miniodtwarzacza powinien być zsynchronizowany ze stanem odtwarzania multimediów na odbiorniku.

8. Powiadomienia i ekran blokady

Lista kontrolna projektu Google Cast wymaga, aby aplikacja wysyłająca implementowała opcje sterowania multimediami z powiadomieniaekranu blokady.

Ilustracja telefonu z Androidem z widocznymi opcjami sterowania multimediami w obszarze powiadomień

Pakiet Cast SDK udostępnia MediaNotificationService, który pomaga aplikacji wysyłającej tworzyć opcje sterowania multimediami w powiadomieniu i na ekranie blokady. Usługa jest automatycznie scalana z manifestem aplikacji przez Gradle.

MediaNotificationService będzie działać w tle, gdy nadawca przesyła treści, i wyświetlać powiadomienie z miniaturą obrazu i metadanymi bieżącego elementu przesyłanego strumieniowo, przyciskiem odtwarzania/wstrzymywania i przyciskiem zatrzymania.

Powiadomienia i elementy sterujące na ekranie blokady można włączyć za pomocą ikony CastOptions podczas inicjowania urządzenia CastContext. Opcje sterowania multimediami w powiadomieniach i na ekranie blokady są domyślnie włączone. Funkcja ekranu blokady jest włączona, dopóki włączone są powiadomienia.

Edytuj CastOptionsProvider i zmień implementację getCastOptions, aby pasowała do tego kodu:

import com.google.android.gms.cast.framework.media.CastMediaOptions
import com.google.android.gms.cast.framework.media.NotificationOptions

override fun getCastOptions(context: Context): CastOptions {
   val notificationOptions = NotificationOptions.Builder()
            .setTargetActivityClassName(VideoBrowserActivity::class.java.name)
            .build()
    val mediaOptions = CastMediaOptions.Builder()
            .setNotificationOptions(notificationOptions)
            .build()
   return CastOptions.Builder()
                .setReceiverApplicationId(context.getString(R.string.app_id))
                .setCastMediaOptions(mediaOptions)
                .build()
}

Kliknij przycisk Przycisk Uruchom w Android Studio, zielony trójkąt skierowany w prawoUruchom, aby uruchomić aplikację na urządzeniu mobilnym. Prześlij film i opuść aplikację przykładową. Powinno pojawić się powiadomienie o filmie odtwarzanym na odbiorniku. Zablokuj urządzenie mobilne. Na ekranie blokady powinny się teraz wyświetlać elementy sterujące odtwarzaniem multimediów na urządzeniu przesyłającym.

Ilustracja przedstawiająca telefon z Androidem z opcjami sterowania multimediami na ekranie blokady

9. Nakładka wprowadzająca

Lista kontrolna projektu Google Cast wymaga, aby aplikacja wysyłająca przedstawiła przycisk Cast dotychczasowym użytkownikom, aby poinformować ich, że aplikacja wysyłająca obsługuje teraz przesyłanie, a także pomaga użytkownikom, którzy dopiero zaczynają korzystać z Google Cast.

Ilustracja przedstawiająca nakładkę wprowadzającą Cast wokół przycisku Cast w aplikacji Cast Videos na Androida

Pakiet Cast SDK udostępnia niestandardowy widok IntroductoryOverlay, który można wykorzystać do wyróżnienia przycisku Cast, gdy po raz pierwszy pojawi się on użytkownikom. Dodaj do pliku VideoBrowserActivity ten kod:

import com.google.android.gms.cast.framework.IntroductoryOverlay
import android.os.Looper

private var mIntroductoryOverlay: IntroductoryOverlay? = null

private fun showIntroductoryOverlay() {
    mIntroductoryOverlay?.remove()
    if (mediaRouteMenuItem?.isVisible == true) {
       Looper.myLooper().run {
           mIntroductoryOverlay = com.google.android.gms.cast.framework.IntroductoryOverlay.Builder(
                    this@VideoBrowserActivity, mediaRouteMenuItem!!)
                   .setTitleText("Introducing Cast")
                   .setSingleTime()
                   .setOnOverlayDismissedListener(
                           object : IntroductoryOverlay.OnOverlayDismissedListener {
                               override fun onOverlayDismissed() {
                                   mIntroductoryOverlay = null
                               }
                          })
                   .build()
          mIntroductoryOverlay!!.show()
        }
    }
}

Teraz dodaj CastStateListener i wywołaj metodę showIntroductoryOverlay, gdy urządzenie przesyłające będzie dostępne. W tym celu zmodyfikuj metodę onCreate i zastąp metody onResumeonPause, aby pasowały do poniższych:

import com.google.android.gms.cast.framework.CastState
import com.google.android.gms.cast.framework.CastStateListener

private var mCastStateListener: CastStateListener? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.video_browser)
    setupActionBar()
    mCastStateListener = object : CastStateListener {
            override fun onCastStateChanged(newState: Int) {
                if (newState != CastState.NO_DEVICES_AVAILABLE) {
                    showIntroductoryOverlay()
                }
            }
        }
    mCastContext = CastContext.getSharedInstance(this)
}

override fun onResume() {
    super.onResume()
    mCastContext?.addCastStateListener(mCastStateListener!!)
}

override fun onPause() {
    super.onPause()
    mCastContext?.removeCastStateListener(mCastStateListener!!)
}

Wyczyść dane aplikacji lub usuń ją z urządzenia. Następnie kliknij przycisk Przycisk Uruchom w Android Studio, zielony trójkąt skierowany w prawoUruchom, aby uruchomić aplikację na urządzeniu mobilnym. Powinien wyświetlić się ekran wprowadzający (jeśli się nie wyświetla, wyczyść dane aplikacji).

10. Rozwinięty kontroler

Lista kontrolna projektu Google Cast wymaga, aby aplikacja wysyłająca udostępniała rozszerzony kontroler dla przesyłanych multimediów. Rozwinięty kontroler to wersja mini kontrolera na pełnym ekranie.

Ilustracja przedstawiająca film odtwarzany na telefonie z Androidem z rozwiniętym kontrolerem na wierzchu

Pakiet Cast SDK udostępnia widżet do rozszerzonego kontrolera o nazwie ExpandedControllerActivity. Jest to klasa abstrakcyjna, którą musisz rozszerzyć, aby dodać przycisk Cast.

Najpierw utwórz nowy plik zasobu menu o nazwie expanded_controller.xml dla rozwiniętego kontrolera, aby udostępnić przycisk Cast:

<?xml version="1.0" encoding="utf-8"?>

<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:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
            app:showAsAction="always"/>

</menu>

Utwórz nowy pakiet expandedcontrols w pakiecie com.google.sample.cast.refplayer. Następnie utwórz nowy plik o nazwie ExpandedControlsActivity.kt w pakiecie com.google.sample.cast.refplayer.expandedcontrols.

package com.google.sample.cast.refplayer.expandedcontrols

import android.view.Menu
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
import com.google.sample.cast.refplayer.R
import com.google.android.gms.cast.framework.CastButtonFactory

class ExpandedControlsActivity : ExpandedControllerActivity() {
    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        super.onCreateOptionsMenu(menu)
        menuInflater.inflate(R.menu.expanded_controller, menu)
        CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item)
        return true
    }
}

Teraz zadeklaruj ExpandedControlsActivityAndroidManifest.xml w tagu application nad tagiem OPTIONS_PROVIDER_CLASS_NAME:

<application>
    ...
    <activity
        android:name="com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:theme="@style/Theme.CastVideosDark"
        android:screenOrientation="portrait"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
        </intent-filter>
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.google.sample.cast.refplayer.VideoBrowserActivity"/>
    </activity>
    ...
</application>

Edytuj CastOptionsProvider i zmień NotificationOptions oraz CastMediaOptions, aby ustawić docelową aktywność na ExpandedControlsActivity:

import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity

override fun getCastOptions(context: Context): CastOptions {
    val notificationOptions = NotificationOptions.Builder()
            .setTargetActivityClassName(ExpandedControlsActivity::class.java.name)
            .build()
    val mediaOptions = CastMediaOptions.Builder()
            .setNotificationOptions(notificationOptions)
            .setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name)
            .build()
    return CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .setCastMediaOptions(mediaOptions)
            .build()
}

Zaktualizuj metodę LocalPlayerActivity loadRemoteMedia, aby wyświetlać ExpandedControlsActivity po wczytaniu zdalnych multimediów:

import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity

private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
    if (mCastSession == null) {
        return
    }
    val remoteMediaClient = mCastSession!!.remoteMediaClient ?: return
    remoteMediaClient.registerCallback(object : RemoteMediaClient.Callback() {
        override fun onStatusUpdated() {
            val intent = Intent(this@LocalPlayerActivity, ExpandedControlsActivity::class.java)
            startActivity(intent)
            remoteMediaClient.unregisterCallback(this)
        }
    })
    remoteMediaClient.load(MediaLoadRequestData.Builder()
                .setMediaInfo(buildMediaInfo())
                .setAutoplay(autoPlay)
                .setCurrentTime(position.toLong()).build())
}

Kliknij przycisk Przycisk Uruchom w Android Studio, zielony trójkąt skierowany w prawoUruchom, aby uruchomić aplikację na urządzeniu mobilnym i przesłać film. Powinien się wyświetlić rozwinięty kontroler. Wróć do listy filmów i kliknij miniodtwarzacz, aby ponownie załadować rozszerzony odtwarzacz. Wyjdź z aplikacji, aby zobaczyć powiadomienie. Kliknij obraz powiadomienia, aby wczytać rozszerzony kontroler.

11. Dodawanie obsługi Cast Connect

Biblioteka Cast Connect umożliwia istniejącym aplikacjom wysyłającym komunikację z aplikacjami na Androida TV za pomocą protokołu Cast. Cast Connect korzysta z infrastruktury Cast, a aplikacja na Androida TV działa jako odbiornik.

Zależności

Uwaga: w przypadku implementacji Cast Connect play-services-cast-framework musi mieć wersję 19.0.0 lub nowszą.

LaunchOptions

Aby uruchomić aplikację na Androida TV, zwaną też odbiornikiem Androida, musimy ustawić flagę setAndroidReceiverCompatible na wartość true w obiekcie LaunchOptions. Ten obiekt LaunchOptions określa sposób uruchomienia odbiornika i jest przekazywany do obiektu CastOptions zwracanego przez klasę CastOptionsProvider. Ustawienie powyższej flagi na false spowoduje uruchomienie odbiornika internetowego dla zdefiniowanego identyfikatora aplikacji w Konsoli programisty Cast.

W pliku CastOptionsProvider.kt dodaj do metody getCastOptions ten kod:

import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
            .setAndroidReceiverCompatible(true)
            .build()
return new CastOptions.Builder()
        .setLaunchOptions(launchOptions)
        ...
        .build()

Ustawianie danych logowania do uruchamiania

Po stronie nadawcy możesz użyć symbolu CredentialsData, aby określić, kto dołącza do sesji. Symbol credentials to ciąg znaków, który może być zdefiniowany przez użytkownika, o ile aplikacja na Androida TV jest w stanie go odczytać. Wartość CredentialsData jest przekazywana do aplikacji na Androida TV tylko podczas uruchamiania lub dołączania. Jeśli ustawisz go ponownie, gdy jesteś połączony, nie zostanie on przekazany do aplikacji na Androida TV.

Aby ustawić dane logowania do uruchamiania, należy zdefiniować parametr CredentialsData i przekazać go do obiektu CredentialsData.LaunchOptions Dodaj ten kod do metody getCastOptions w pliku CastOptionsProvider.kt:

import com.google.android.gms.cast.CredentialsData
...

val credentialsData = CredentialsData.Builder()
        .setCredentials("{\"userId\": \"abc\"}")
        .build()
val launchOptions = LaunchOptions.Builder()
       ...
       .setCredentialsData(credentialsData)
       .build()

Ustawianie danych logowania w obiekcie LoadRequest

Jeśli aplikacja odbiornika internetowego i aplikacja na Androida TV obsługują credentials w inny sposób, może być konieczne zdefiniowanie osobnych credentials dla każdej z nich. Aby to zrobić, dodaj ten kod do pliku LocalPlayerActivity.kt pod funkcją loadRemoteMedia:

remoteMediaClient.load(MediaLoadRequestData.Builder()
       ...
       .setCredentials("user-credentials")
       .setAtvCredentials("atv-user-credentials")
       .build())

W zależności od aplikacji odbiorcy, do której nadawca przesyła treści, pakiet SDK będzie teraz automatycznie określać, których danych logowania użyć w bieżącej sesji.

Testowanie Cast Connect

Instalowanie pliku APK Androida TV na urządzeniu Chromecast z Google TV

  1. Znajdź adres IP urządzenia z Androidem TV. Zwykle jest on dostępny w sekcji Ustawienia > Sieć i internet > (Nazwa sieci, z którą połączone jest urządzenie). Po prawej stronie wyświetlą się szczegóły i adres IP urządzenia w sieci.
  2. Użyj adresu IP urządzenia, aby połączyć się z nim za pomocą ADB w terminalu:
$ adb connect <device_ip_address>:5555
  1. W oknie terminala przejdź do folderu najwyższego poziomu z przykładowymi plikami do tego ćwiczenia, który został pobrany na początku. Na przykład:
$ cd Desktop/android_codelab_src
  1. Zainstaluj plik APK w tym folderze na Androidzie TV, uruchamiając to polecenie:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. W menu Twoje aplikacje na urządzeniu z Androidem TV powinna być teraz widoczna aplikacja o nazwie Przesyłaj filmy.
  2. Wróć do projektu Android Studio i kliknij przycisk Uruchom, aby zainstalować i uruchomić aplikację nadawcy na fizycznym urządzeniu mobilnym. W prawym górnym rogu kliknij ikonę przesyłania i wybierz urządzenie z Androidem TV z dostępnych opcji. Aplikacja na Androida TV powinna się teraz uruchomić na urządzeniu z Androidem TV, a odtwarzanie filmu powinno umożliwić sterowanie odtwarzaniem za pomocą pilota Android TV.

12. Dostosowywanie widżetów Cast

Możesz dostosować widżety Cast, ustawiając kolory, stylizując przyciski, tekst i wygląd miniatur oraz wybierając typy przycisków do wyświetlania.

Zaktualizuj: res/values/styles_castvideo.xml

<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
    <item name="castIntroOverlayStyle">@style/CustomCastIntroOverlay</item>
    <item name="castMiniControllerStyle">@style/CustomCastMiniController</item>
    <item name="castExpandedControllerStyle">@style/CustomCastExpandedController</item>
    <item name="castExpandedControllerToolbarStyle">
        @style/ThemeOverlay.AppCompat.ActionBar
    </item>
    ...
</style>

Zadeklaruj te motywy niestandardowe:

<!-- Customize Cast Button -->
<style name="CustomMediaRouterTheme" parent="Theme.MediaRouter">
    <item name="mediaRouteButtonStyle">@style/CustomMediaRouteButtonStyle</item>
</style>
<style name="CustomMediaRouteButtonStyle" parent="Widget.MediaRouter.Light.MediaRouteButton">
    <item name="mediaRouteButtonTint">#EEFF41</item>
</style>

<!-- Customize Introductory Overlay -->
<style name="CustomCastIntroOverlay" parent="CastIntroOverlay">
    <item name="castButtonTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Button</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Title</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Button" parent="android:style/TextAppearance">
    <item name="android:textColor">#FFFFFF</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Title" parent="android:style/TextAppearance.Large">
    <item name="android:textColor">#FFFFFF</item>
</style>

<!-- Customize Mini Controller -->
<style name="CustomCastMiniController" parent="CastMiniController">
    <item name="castShowImageThumbnail">true</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.AppCompat.Subhead</item>
    <item name="castSubtitleTextAppearance">@style/TextAppearance.AppCompat.Caption</item>
    <item name="castBackground">@color/accent</item>
    <item name="castProgressBarColor">@color/orange</item>
</style>

<!-- Customize Expanded Controller -->
<style name="CustomCastExpandedController" parent="CastExpandedController">
    <item name="castButtonColor">#FFFFFF</item>
    <item name="castPlayButtonDrawable">@drawable/cast_ic_expanded_controller_play</item>
    <item name="castPauseButtonDrawable">@drawable/cast_ic_expanded_controller_pause</item>
    <item name="castStopButtonDrawable">@drawable/cast_ic_expanded_controller_stop</item>
</style>

13. Gratulacje

Wiesz już, jak włączyć przesyłanie w aplikacji wideo za pomocą widżetów pakietu Cast SDK na Androidzie.

Więcej informacji znajdziesz w przewodniku dla programistów Android Sender.