1. Übersicht
In diesem Codelab erfahren Sie, wie Sie eine vorhandene Android-Video-App ändern, um Inhalte auf ein für Google Cast optimiertes Gerät zu streamen.
Was ist Google Cast?
Mit Google Cast können Nutzer Inhalte von einem Mobilgerät auf einen Fernseher streamen. Nutzer können ihr Mobilgerät dann als Fernbedienung für die Medienwiedergabe auf dem Fernseher verwenden.
Mit dem Google Cast SDK können Sie Ihre App erweitern, um einen Fernseher oder ein Soundsystem zu steuern. Mit dem Cast SDK können Sie die erforderlichen UI-Komponenten gemäß der Google Cast-Design-Checkliste hinzufügen.
Die Checkliste für das Design von Google Cast soll es Nutzern der Cast-Nutzung auf allen unterstützten Plattformen erleichtern.
Ziele
Nach Abschluss dieses Codelabs hast du eine Android-Video-App, mit der du Videos auf ein für Google Cast optimiertes Gerät streamen kannst.
Lerninhalte
- Das Google Cast SDK einer Beispielvideo-App hinzufügen
- Hier erfährst du, wie du das Cast-Symbol zur Auswahl eines Google Cast-Geräts hinzufügst.
- Verbindung zu einem Cast-Gerät herstellen und einen Medienempfänger starten.
- So streamen Sie ein Video
- So fügen Sie Ihrer App einen Cast Mini-Controller hinzu
- Medienbenachrichtigungen und Steuerelemente für den Sperrbildschirm unterstützen
- So fügen Sie einen erweiterten Controller hinzu:
- Einführungs-Overlay bereitstellen
- Cast-Widgets anpassen
- Integration in Cast Connect
Voraussetzungen
- Das aktuelle Android SDK.
- Android Studio Version 3.2 oder höher
- Ein Mobilgerät mit Jelly Bean ab Android 4.1 (API-Level 16).
- Ein USB-Datenkabel zum Verbinden Ihres Mobilgeräts mit Ihrem Entwicklungscomputer.
- Ein Google Cast-Gerät wie Chromecast oder Android TV, das mit dem Internet verbunden ist.
- Fernseher oder Monitor mit HDMI-Eingang
- Zum Testen der Cast Connect-Integration ist Chromecast mit Google TV erforderlich, für den Rest des Codelabs aber optional. Wenn Sie keine haben, überspringen Sie den Schritt Cast Connect-Unterstützung hinzufügen gegen Ende dieser Anleitung.
Plattform
- Sie benötigen dafür Vorkenntnisse in Kotlin und Android.
- Außerdem benötigst du Vorkenntnisse zum Fernsehen.
Wie werden Sie diese Anleitung verwenden?
Wie würden Sie Ihre Erfahrungen im Entwickeln von Android-Apps bewerten?
Wie würdest du deine Erfahrung beim Fernsehen bewerten?
2. Beispielcode abrufen
Sie können den gesamten Beispielcode auf Ihren Computer herunterladen...
und entpacken Sie die heruntergeladene ZIP-Datei.
3. Beispiel-App ausführen
Sehen wir uns zuerst die fertige Beispiel-App an. Die App ist ein einfacher Videoplayer. Der Nutzer kann ein Video aus einer Liste auswählen und es dann lokal auf dem Gerät wiedergeben oder auf ein Google Cast-Gerät streamen.
Nachdem der Code heruntergeladen wurde, wird anhand der folgenden Anleitung beschrieben, wie Sie die ausgefüllte Beispiel-App in Android Studio öffnen und ausführen:
Wählen Sie im Begrüßungsbildschirm die Option Projekt importieren oder die Menüoptionen Datei > Neu > Projekt importieren... aus.
Wählen Sie das Verzeichnis app-done
aus dem Beispielcodeordner aus und klicken Sie auf „OK“.
Klicken Sie auf Datei > Projekt mit Gradle-Dateien synchronisieren.
USB-Debugging auf Android-Geräten aktivieren: Unter Android 4.2 und höher ist der Bildschirm mit den Entwickleroptionen standardmäßig ausgeblendet. Rufen Sie dazu Einstellungen > Über das Telefon auf und tippen Sie siebenmal auf Build-Nummer. Kehren Sie zum vorherigen Bildschirm zurück, wählen Sie System > Erweitert aus und tippen Sie unten auf Entwickleroptionen. Tippen Sie dann auf USB-Debugging, um es zu aktivieren.
Schließe dein Android-Gerät an und klicke in Android Studio auf die Schaltfläche Ausführen. Nach einigen Sekunden sollte die Video-App Videos streamen angezeigt werden.
Klicken Sie in der Video-App auf das Cast-Symbol und wählen Sie Ihr Google Cast-Gerät aus.
Wähle ein Video aus und klicke auf die Wiedergabeschaltfläche.
Das Video wird auf Ihrem Google Cast-Gerät abgespielt.
Der maximierte Controller wird angezeigt. Mit der Schaltfläche „Wiedergabe/Pause“ kannst du die Wiedergabe steuern.
Zurück zur Videoliste
Unten auf dem Bildschirm ist jetzt ein Mini-Controller zu sehen.
Klicke auf die Pause-Taste im Mini-Controller, um das Video auf dem Receiver zu pausieren. Klicke auf die Wiedergabeschaltfläche im Minicontroller, um die Wiedergabe des Videos fortzusetzen.
Klicken Sie auf die Startbildschirmtaste des Mobilgeräts. Wischen Sie nach unten, um eine Benachrichtigung für die Streamingsitzung zu sehen.
Wenn du dein Smartphone sperrst, sollte auf dem Sperrbildschirm eine Benachrichtigung angezeigt werden, mit der du die Medienwiedergabe steuern und das Streamen beenden kannst.
Kehren Sie zur Video-App zurück und klicken Sie auf das Cast-Symbol, um das Streaming auf dem Google Cast-Gerät zu beenden.
Häufig gestellte Fragen
4. Startprojekt vorbereiten
Wir müssen die heruntergeladene Start-App für Google Cast unterstützen. Hier sind einige Google Cast-Begriffe, die wir in diesem Codelab verwenden werden:
- Eine Absender-App wird auf einem Mobilgerät oder Laptop ausgeführt.
- Eine Empfänger-App wird auf dem Google Cast-Gerät ausgeführt.
Jetzt können Sie auf dem Startprojekt mit Android Studio aufbauen:
- Wählen Sie das Verzeichnis
app-start
aus dem Beispielcode aus (wählen Sie auf der Begrüßungsseite Projekt importieren oder die Menüoption Datei > Neu > Projekt importieren...). - Klicken Sie auf die Schaltfläche
Sync Project with Gradle Files (Projekt mit Gradle-Dateien synchronisieren).
- Klicken Sie auf die Schaltfläche
Ausführen, um die App auszuführen und die Benutzeroberfläche kennenzulernen.
App-Design
Die App ruft eine Liste von Videos von einem Remote-Webserver ab und stellt dem Nutzer eine Liste zur Verfügung. Nutzer können ein Video auswählen, um sich die Details anzusehen, oder das Video lokal auf dem Mobilgerät abspielen.
Die App besteht aus zwei Hauptaktivitäten: VideoBrowserActivity
und LocalPlayerActivity
. Damit die Google Cast-Funktionen eingebunden werden können, müssen die Aktivitäten entweder vom AppCompatActivity
oder vom übergeordneten Element FragmentActivity
übernommen werden. Diese Einschränkung besteht, da wir MediaRouteButton
(in der MediaRouter-Supportbibliothek enthalten) als MediaRouteActionProvider
hinzufügen müssen und dies nur funktioniert, wenn die Aktivität von den oben genannten Klassen übernommen wird. Die MediaRouter-Supportbibliothek hängt von der AppCompat-Supportbibliothek ab, die die erforderlichen Klassen enthält.
VideoBrowserActivity
Diese Aktivität enthält eine Fragment
(VideoBrowserFragment
). Diese Liste wird durch ein ArrayAdapter
(VideoListAdapter
) gesichert. Die Liste der Videos und die zugehörigen Metadaten werden als JSON-Datei auf einem Remote-Server gehostet. Ein AsyncTaskLoader
(VideoItemLoader
) ruft dieses JSON ab und verarbeitet es, um eine Liste von MediaItem
-Objekten zu erstellen.
Ein MediaItem
-Objekt modelliert ein Video und die zugehörigen Metadaten, z. B. Titel, Beschreibung, URL für den Stream, URL für die unterstützenden Bilder und ggf. zugehörige Text-Tracks (für Untertitel). Das MediaItem
-Objekt wird zwischen Aktivitäten übergeben. In MediaItem
gibt es Dienstmethoden, um es in Bundle
umzuwandeln und umgekehrt.
Wenn der Loader die Liste von MediaItems
erstellt, übergibt er diese Liste an die VideoListAdapter
, die dann die MediaItems
-Liste in VideoBrowserFragment
präsentiert. Dem Nutzer wird eine Liste mit Video-Thumbnails mit einer kurzen Beschreibung für jedes Video angezeigt. Wenn ein Element ausgewählt wird, wird die entsprechende MediaItem
in eine Bundle
umgewandelt und an die LocalPlayerActivity
übergeben.
Lokale Player-Aktivität
Bei dieser Aktivität werden die Metadaten zu einem bestimmten Video angezeigt und der Nutzer kann das Video lokal auf dem Mobilgerät abspielen.
Die Aktivität enthält ein VideoView
-Element, einige Mediensteuerelemente und einen Textbereich, in dem die Beschreibung des ausgewählten Videos angezeigt wird. Der Player deckt den oberen Teil des Bildschirms ab. So bleibt Platz für eine detaillierte Beschreibung des Videos unten. Der Nutzer kann Videos abspielen/anhalten oder die lokale Wiedergabe von Videos starten.
Abhängigkeiten
Da wir AppCompatActivity
verwenden, benötigen wir die AppCompat-Supportbibliothek. Zur Verwaltung der Videoliste und zum asynchronen Abrufen der Bilder für die Liste verwenden wir die Bibliothek Volley.
Häufig gestellte Fragen
5. Cast-Symbol hinzufügen
Eine Cast-fähige App zeigt bei jeder Aktivität das Cast-Symbol an. Durch Klicken auf das Cast-Symbol wird eine Liste der Übertragungsgeräte angezeigt, die der Nutzer auswählen kann. Wenn der Nutzer Inhalte lokal auf dem Absendergerät abspielt, wird die Wiedergabe auf diesem Gerät gestartet oder fortgesetzt. Der Nutzer kann während des Streamens jederzeit auf das Cast-Symbol klicken und die Übertragung der App auf das Übertragungsgerät beenden. Der Nutzer muss in der Lage sein, sich während einer beliebigen Aktivität Ihrer App mit dem Cast-Gerät zu verbinden oder die Verbindung damit zu trennen, wie in der Google Cast-Design-Checkliste beschrieben.
Abhängigkeiten
Aktualisieren Sie die build.gradle-Datei der App, um die erforderlichen Bibliotheksabhängigkeiten aufzunehmen:
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"
}
Synchronisieren Sie das Projekt, um zu prüfen, ob es fehlerfrei erstellt wurde.
Initialisierung
Das Cast-Framework hat ein globales Singleton-Objekt, das CastContext
, das alle Cast-Interaktionen koordiniert.
Sie müssen die OptionsProvider
-Schnittstelle implementieren, um die CastOptions
bereitzustellen, die zur Initialisierung des CastContext
-Singleton benötigt wird. Die wichtigste Option ist die ID der Empfängeranwendung. Damit werden die Ergebnisse der Cast-Geräteerkennung gefiltert und die Empfängeranwendung gestartet, wenn eine Cast-Sitzung gestartet wird.
Wenn Sie Ihre eigene Cast-fähige App entwickeln, müssen Sie sich als Cast-Entwickler registrieren und dann eine App-ID für Ihre App abrufen. Für dieses Codelab verwenden wir eine Beispiel-App-ID.
Fügen Sie dem com.google.sample.cast.refplayer
-Paket des Projekts die folgende neue CastOptionsProvider.kt
-Datei hinzu:
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
}
}
Deklariere jetzt OptionsProvider
im Tag "application
" der AndroidManifest.xml
-Datei der App:
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />
Initialisieren Sie CastContext
ausführlich mit der onCreate-Methode VideoBrowserActivity
:
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)
}
Fügen Sie LocalPlayerActivity
die gleiche Initialisierungslogik hinzu.
Cast-Symbol
Nachdem die CastContext
initialisiert wurde, müssen wir das Cast-Symbol hinzufügen, damit der Nutzer ein Übertragungsgerät auswählen kann. Das Cast-Symbol wird von MediaRouteButton
aus der MediaRouter-Supportbibliothek implementiert. Wie bei jedem Aktionssymbol, das Sie Ihren Aktivitäten über ein ActionBar
- oder Toolbar
-Element hinzufügen können, müssen Sie zuerst dem Menü den entsprechenden Menüpunkt hinzufügen.
Bearbeiten Sie die Datei res/menu/browse.xml
und fügen Sie im Menü vor den Einstellungen das Element MediaRouteActionProvider
hinzu:
<item
android:id="@+id/media_route_menu_item"
android:title="@string/media_route_menu_title"
app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
app:showAsAction="always"/>
Überschreiben Sie die Methode onCreateOptionsMenu()
von VideoBrowserActivity
mit CastButtonFactory
, um MediaRouteButton
mit dem Cast-Framework zu verbinden:
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
}
Überschreiben Sie onCreateOptionsMenu
in LocalPlayerActivity
auf ähnliche Weise.
Klicken Sie auf die Schaltfläche Ausführen, um die App auf Ihrem Mobilgerät auszuführen. In der Aktionsleiste der App sollte ein Cast-Symbol zu sehen sein. Wenn Sie darauf klicken, werden die Cast-Geräte in Ihrem lokalen Netzwerk aufgelistet. Die Geräteerkennung wird automatisch von
CastContext
verwaltet. Wählen Sie Ihr Übertragungsgerät aus. Die Beispiel-Empfänger-App wird dann auf dem Übertragungsgerät geladen. Sie können zwischen der Browseraktivität und der lokalen Spieleraktivität wechseln und der Status des Cast-Symbols wird synchronisiert.
Wir haben keine Medienunterstützung aktiviert, sodass du noch keine Videos über das Cast-Gerät abspielen kannst. Klicken Sie auf das Cast-Symbol, um die Verbindung zu trennen.
6. Videoinhalte streamen
Die Beispiel-App wird erweitert, damit du Videos auch per Fernzugriff auf einem Übertragungsgerät wiedergeben kannst. Dazu müssen wir die verschiedenen Ereignisse beobachten, die vom Cast-Framework generiert werden.
Medien streamen
Wenn Sie Medien auf einem Übertragungsgerät abspielen möchten, gehen Sie so vor:
- Erstellen Sie ein
MediaInfo
-Objekt, mit dem ein Medienelement modelliert wird. - Stellen Sie eine Verbindung zum Übertragungsgerät her und starten Sie die Empfängeranwendung.
- Laden Sie das
MediaInfo
-Objekt in den Receiver und spielen Sie den Inhalt ab. - Medienstatus verfolgen
- Sende Wiedergabebefehle basierend auf Nutzerinteraktionen an den Empfänger.
Wir haben Schritt 2 bereits im vorherigen Abschnitt ausgeführt. Schritt 3 ist mit dem Cast-Framework ganz einfach. Schritt 1 ist die Zuordnung eines Objekts zu einem anderen. MediaInfo
ist etwas, das vom Cast-Framework verstanden wird, und MediaItem
ist die Kapselung unserer App für ein Mediakosten. Wir können MediaItem
einfach einem MediaInfo
zuordnen.
Die Beispiel-App LocalPlayerActivity
unterscheidet mithilfe der folgenden Aufzählung bereits zwischen der lokalen und der Remote-Wiedergabe:
private var mLocation: PlaybackLocation? = null
enum class PlaybackLocation {
LOCAL, REMOTE
}
enum class PlaybackState {
PLAYING, PAUSED, BUFFERING, IDLE
}
In diesem Codelab ist es nicht wichtig, dass du genau verstehst, wie die Beispielplayerlogik funktioniert. Es ist wichtig zu verstehen, dass der Mediaplayer Ihrer App so angepasst werden muss, dass die beiden Wiedergabeorte auf ähnliche Weise erkannt werden.
Momentan ist der lokale Player immer im lokalen Wiedergabestatus, da er noch nichts über den Streamingstatus weiß. Wir müssen die Benutzeroberfläche basierend auf Statusübergängen aktualisieren, die im Cast-Framework stattfinden. Wenn wir beispielsweise mit der Übertragung beginnen, müssen wir die lokale Wiedergabe beenden und einige Steuerelemente deaktivieren. Wenn wir in diesem Fall das Streaming beenden, müssen wir zur lokalen Wiedergabe übergehen. Dazu müssen wir die verschiedenen Ereignisse überwachen, die vom Cast-Framework generiert werden.
Cast-Sitzungsverwaltung
Beim Cast-Framework umfasst eine Cast-Sitzung die Schritte zum Herstellen einer Verbindung zu einem Gerät, zum Starten bzw. zum Beitritt, zum Herstellen einer Verbindung mit einer Empfängeranwendung und zum Initialisieren eines Mediensteuerkanals. Der Mediensteuerungskanal ist die Methode, mit der das Cast-Framework Nachrichten vom Mediaplayer des Empfängers sendet und empfängt.
Die Streamingsitzung wird automatisch gestartet, wenn der Nutzer ein Gerät über das Cast-Symbol auswählt, und wird automatisch beendet, wenn der Nutzer die Verbindung trennt. Die Verbindung zu einer Empfängersitzung aufgrund von Netzwerkproblemen wird auch automatisch vom Cast SDK verarbeitet.
Fügen wir dem LocalPlayerActivity
ein SessionManagerListener
hinzu:
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()
}
}
}
Bei Aktivitäten im Zusammenhang mit LocalPlayerActivity
möchten wir darüber informiert werden, wenn die Verbindung zum Cast-Gerät getrennt oder getrennt wird, damit wir zum lokalen Player wechseln können. Beachten Sie, dass die Verbindung nicht nur durch die Instanz Ihrer Anwendung unterbrochen werden kann, sondern auch durch eine andere Instanz Ihrer Anwendung (oder eine andere Anwendung), die auf einem anderen Mobilgerät ausgeführt wird.
Auf die aktuell aktive Sitzung kann über SessionManager.getCurrentSession()
zugegriffen werden. Sitzungen werden als Reaktion auf Nutzerinteraktionen mit den Cast-Dialogfeldern automatisch erstellt und gelöscht.
Wir müssen unseren Sitzungs-Listener registrieren und einige Variablen initialisieren, die wir in der Aktivität verwenden werden. Ändern Sie die Methode LocalPlayerActivity
onCreate
in:
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)
}
}
...
}
Medien werden geladen
Im Cast SDK bietet der RemoteMediaClient
eine Reihe praktischer APIs zur Verwaltung der Remote-Medienwiedergabe auf dem Empfänger. Bei einem CastSession
, der die Medienwiedergabe unterstützt, wird vom SDK automatisch eine Instanz von RemoteMediaClient
erstellt. Der Zugriff erfolgt über die Methode getRemoteMediaClient()
in der Instanz CastSession
. Füge die folgenden Methoden zu LocalPlayerActivity
hinzu, um das aktuell ausgewählte Video auf dem Empfänger zu laden:
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()
}
}
Aktualisieren Sie nun verschiedene vorhandene Methoden, um die Cast-Sitzungslogik zur Remote-Wiedergabe zu verwenden:
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()
}
Ändern Sie für die Methode updatePlayButton
den Wert der Variablen isConnected
:
private fun updatePlayButton(state: PlaybackState?) {
...
val isConnected = (mCastSession != null
&& (mCastSession!!.isConnected || mCastSession!!.isConnecting))
...
}
Klicken Sie jetzt auf Ausführen, um die App auf Ihrem Mobilgerät auszuführen. Stelle eine Verbindung zu deinem Übertragungsgerät her und starte die Wiedergabe eines Videos. Das Video sollte auf dem Receiver wiedergegeben werden.
7. Mini-Controller
Gemäß der Checkliste für das Cast-Design muss jede Cast-App einen Mini-Controller bereitstellen, der angezeigt wird, wenn der Nutzer die aktuelle Inhaltsseite verlässt. Der Mini-Controller bietet sofortigen Zugriff und eine sichtbare Erinnerung für die aktuelle Streamingsitzung.
Das Cast SDK bietet eine benutzerdefinierte Ansicht, MiniControllerFragment
, die du der App-Layoutdatei der Aktivitäten hinzufügen kannst, in denen der Minicontroller angezeigt werden soll.
Fügen Sie unten in res/layout/player_activity.xml
und res/layout/video_browser.xml
die folgende Fragmentdefinition ein:
<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"/>
Klicken Sie auf die Schaltfläche Ausführen, um die App auszuführen und ein Video zu streamen. Wenn die Wiedergabe auf dem Receiver beginnt, sollte unten auf jeder Aktivität der Minicontroller angezeigt werden. Sie können die Wiedergabe über den Mini-Controller steuern. Wenn Sie zwischen der Browseraktivität und der lokalen Player-Aktivität wechseln, sollte der Mini-Controller-Status mit dem Medienwiedergabestatus des Empfängers synchron bleiben.
8. Benachrichtigung und Sperrbildschirm
In der Checkliste für das Design von Google Cast muss die Absender-App Mediensteuerelemente über eine Benachrichtigung und den Sperrbildschirm implementieren.
Das Cast SDK enthält ein MediaNotificationService
, mit dem die Sender-App Mediensteuerelemente für die Benachrichtigung und den Sperrbildschirm erstellen kann. Der Dienst wird von Gradle automatisch in das Manifest Ihrer App zusammengeführt.
MediaNotificationService
wird beim Streamen im Hintergrund ausgeführt und zeigt eine Benachrichtigung mit einem Bild-Thumbnail sowie Metadaten zum aktuellen Streaming-Element, einer Wiedergabe-/Pause-Schaltfläche und einer Stopp-Schaltfläche an.
Die Benachrichtigungs- und Sperrbildschirmsteuerelemente können beim Initialisieren der CastContext
mit CastOptions
aktiviert werden. Die Mediensteuerung für Benachrichtigungen und Sperrbildschirm ist standardmäßig aktiviert. Die Sperrfunktion ist aktiviert, solange Benachrichtigungen aktiviert sind.
Bearbeiten Sie CastOptionsProvider
und ändern Sie die getCastOptions
-Implementierung so, dass sie diesem Code entspricht:
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()
}
Klicken Sie auf die Schaltfläche Ausführen, um die App auf Ihrem Mobilgerät auszuführen. Streamen Sie ein Video und verlassen Sie die Beispiel-App. Es sollte eine Benachrichtigung für das Video angezeigt werden, das gerade auf dem Empfänger wiedergegeben wird. Wenn Sie Ihr Mobilgerät sperren, sollten auf dem Sperrbildschirm jetzt Steuerelemente für die Medienwiedergabe auf dem Übertragungsgerät angezeigt werden.
9. Einführungs-Overlay
In der Checkliste für das Design von Google Cast muss eine Absender-App das Cast-Symbol bestehenden Nutzern zur Verfügung stellen, um sie darüber zu informieren, dass die Absender-App jetzt das Streamen unterstützt und außerdem Nutzern hilft, neu bei Google Cast zu werden.
Das Cast SDK bietet eine benutzerdefinierte Ansicht, IntroductoryOverlay
, mit der Sie das Cast-Symbol hervorheben können, wenn es Nutzern zum ersten Mal angezeigt wird. Fügen Sie VideoBrowserActivity
den folgenden Code hinzu:
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()
}
}
}
Fügen Sie jetzt ein CastStateListener
hinzu und rufen Sie die Methode showIntroductoryOverlay
auf, wenn ein Übertragungsgerät verfügbar ist. Ändern Sie dazu die Methode onCreate
und überschreiben Sie die Methoden onResume
und onPause
so:
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!!)
}
Löschen Sie die App-Daten oder entfernen Sie die App von Ihrem Gerät. Klicken Sie dann auf Ausführen, um die App auf Ihrem Mobilgerät auszuführen, und das Einführungs-Overlay wird angezeigt. Falls das Overlay nicht angezeigt wird, löschen Sie die App-Daten.
10. Maximierter Controller
In der Checkliste für das Design von Google Cast muss eine Absender-App einen erweiterten Controller für die gestreamten Medien bereitstellen. Der maximierte Controller ist eine Vollbildversion des Mini-Controllers.
Das Cast SDK umfasst ein Widget für den erweiterten Controller mit dem Namen ExpandedControllerActivity
. Dies ist eine abstrakte Klasse, die Sie erstellen müssen, um eine Unterklasse hinzuzufügen.
Erstellen Sie zuerst eine neue Menüressourcendatei namens expanded_controller.xml
für den maximierten Controller, um das Cast-Symbol bereitzustellen:
<?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>
Erstellen Sie ein neues expandedcontrols
-Paket im com.google.sample.cast.refplayer
-Paket. Erstellen Sie als Nächstes eine neue Datei mit dem Namen ExpandedControlsActivity.kt
im Paket 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
}
}
Deklariere jetzt ExpandedControlsActivity
im AndroidManifest.xml
innerhalb des application
-Tags über 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>
Bearbeiten Sie CastOptionsProvider
und ändern Sie NotificationOptions
und CastMediaOptions
, um die Zielaktivität auf ExpandedControlsActivity
festzulegen:
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()
}
Aktualisieren Sie die LocalPlayerActivity
-Methode loadRemoteMedia
, damit ExpandedControlsActivity
angezeigt wird, wenn das Remote-Medien geladen wird:
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())
}
Klicken Sie auf die Schaltfläche Ausführen, um die App auf Ihrem Mobilgerät auszuführen und ein Video zu streamen. Der maximierte Controller sollte angezeigt werden. Kehren Sie zur Liste der Videos zurück. Wenn Sie auf den Minicontroller klicken, wird der maximierte Controller wieder geladen. Verlassen Sie die App, um die Benachrichtigung zu sehen. Klicken Sie auf das Benachrichtigungsbild, um den maximierten Controller zu laden.
11. Cast Connect-Unterstützung hinzufügen
Mit der Cast Connect-Bibliothek können bestehende Absender-Apps über Android Cast mit Android TV-Apps kommunizieren. Cast Connect baut auf der Cast-Infrastruktur auf, wobei deine Android TV App als Empfänger fungiert.
Abhängigkeiten
Hinweis: Für die Implementierung von Cast Connect muss play-services-cast-framework
19.0.0
oder höher sein.
Einführungsoptionen
Zum Starten der App für Android TV, auch Android Receiver genannt, müssen Sie das setAndroidReceiverCompatible
-Objekt im Objekt LaunchOptions
auf „true“ setzen. Dieses LaunchOptions
-Objekt gibt vor, wie der Empfänger gestartet wird, und wird an die CastOptions
übergeben, die von der Klasse CastOptionsProvider
zurückgegeben wird. Wenn Sie das oben genannte Flag auf false
setzen, wird der Webempfänger für die definierte App-ID in der Cast Developer Console gestartet.
Fügen Sie in der Datei CastOptionsProvider.kt
Folgendes zur getCastOptions
-Methode hinzu:
import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
.setAndroidReceiverCompatible(true)
.build()
return new CastOptions.Builder()
.setLaunchOptions(launchOptions)
...
.build()
Anmeldedaten für die Einführung festlegen
Auf der Seite des Absenders können Sie angeben, wer CredentialsData
der Sitzung beitreten darf. credentials
ist ein String, der vom Nutzer definiert werden kann, solange Ihre ATV-App ihn verstehen kann. Die CredentialsData
wird nur während des Starts oder beim Beitritt an deine Android TV App übertragen. Wenn Sie sie noch einmal einrichten, während Sie verbunden sind, wird sie nicht an Ihre Android TV App übertragen.
Zum Festlegen von Anmeldeinformationen muss CredentialsData
definiert und an das LaunchOptions
-Objekt übergeben werden. Fügen Sie der Datei getCastOptions
in der Datei CastOptionsProvider.kt
den folgenden Code hinzu:
import com.google.android.gms.cast.CredentialsData
...
val credentialsData = CredentialsData.Builder()
.setCredentials("{\"userId\": \"abc\"}")
.build()
val launchOptions = LaunchOptions.Builder()
...
.setCredentialsData(credentialsData)
.build()
Anmeldedaten für LoadRequest festlegen
Wenn die Web Receiver App und die Android TV App credentials
unterschiedlich verarbeiten, müssen Sie möglicherweise für jede eine separate credentials
definieren. Fügen Sie der Datei LocalPlayerActivity.kt
unter der Funktion loadRemoteMedia
den folgenden Code hinzu:
remoteMediaClient.load(MediaLoadRequestData.Builder()
...
.setCredentials("user-credentials")
.setAtvCredentials("atv-user-credentials")
.build())
Je nachdem, an welche Empfänger-App der Absender streamt, verarbeitet das SDK jetzt automatisch, welche Anmeldedaten für die aktuelle Sitzung verwendet werden sollen.
Cast Connect testen
Android TV-APK auf Chromecast mit Google TV installieren
- Suchen Sie die IP-Adresse Ihres Android TV-Geräts. Sie finden diese Option in der Regel unter Einstellungen > Netzwerk & Internet > (Netzwerkname, mit dem Ihr Gerät verbunden ist). Rechts werden die Details und die IP-Adresse Ihres Geräts im Netzwerk angezeigt.
- Verwenden Sie die IP-Adresse für Ihr Gerät, um über ADB eine Verbindung über das Terminal herzustellen:
$ adb connect <device_ip_address>:5555
- Gehen Sie im Terminalfenster zum Ordner der obersten Ebene für die Codelab-Beispiele, die Sie zu Beginn dieses Codelabs heruntergeladen haben. Beispiel:
$ cd Desktop/android_codelab_src
- Installieren Sie die APK-Datei in diesem Ordner auf Ihrem Android TV:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Auf Ihrem Android TV-Gerät sollte jetzt im Menü Meine Apps eine App mit dem Namen Videos streamen zu sehen sein.
- Kehren Sie zu Ihrem Android Studio-Projekt zurück und klicken Sie auf „Ausführen“, um die Absender-App auf Ihrem Mobilgerät zu installieren und auszuführen. Klicken Sie rechts oben auf das Cast-Symbol und wählen Sie Ihr Android TV-Gerät aus den verfügbaren Optionen aus. Die Android TV App sollte jetzt auf Ihrem Android TV-Gerät gestartet werden. Wenn Sie ein Video abspielen, sollten Sie die Wiedergabe über die Android TV-Fernbedienung steuern können.
12. Cast-Widgets anpassen
Sie können Cast-Widgets anpassen, indem Sie die Farben, den Stil der Schaltflächen, den Text und die Darstellung der Miniaturansichten sowie die angezeigten Schaltflächen festlegen.
res/values/styles_castvideo.xml
aktualisieren
<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>
Folgende benutzerdefinierte Designs deklarieren:
<!-- 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. Glückwunsch
Jetzt wissen Sie, wie Sie eine Video-App mithilfe der Cast SDK-Widgets auf Android-Geräten aktivieren.
Weitere Informationen finden Sie im Entwicklerleitfaden Android Sender.