1. Übersicht
In diesem Codelab erfahren Sie, wie Sie eine vorhandene Android-Video-App so ändern, dass Inhalte auf einem für Google Cast optimierten Gerät gestreamt werden können.
Was ist Google Cast?
Mit Google Cast können Nutzer Inhalte von Mobilgeräten auf einen Fernseher streamen. Nutzer können dann ihr Mobilgerät als Fernbedienung für die Medienwiedergabe auf dem Fernseher verwenden.
Mit dem Google Cast SDK können Sie Ihre App so erweitern, dass sie einen Fernseher oder ein Soundsystem steuern kann. Mit dem Cast SDK können Sie die erforderlichen UI-Komponenten anhand der Google Cast-Design-Checkliste hinzufügen.
Die Checkliste für das Google Cast-Design wurde bereitgestellt, um die Nutzung von Cast auf allen unterstützten Plattformen einfach und vorhersehbar zu machen.
Ziele
Wenn Sie dieses Codelab abgeschlossen haben, haben Sie eine Android-Video-App, mit der Sie Videos auf ein Google Cast-kompatibles Gerät streamen können.
Lerninhalte
- So fügen Sie einer Beispiel-Video-App das Google Cast SDK hinzu.
- So fügen Sie die Schaltfläche „Streamen“ zum Auswählen eines Google Cast-Geräts hinzu.
- Verbindung zu einem Übertragungsgerät herstellen und einen Medienempfänger starten
- So streamen Sie ein Video.
- So fügen Sie Ihrer App einen Cast-Mini-Controller hinzu.
- Unterstützung von Medienbenachrichtigungen und Sperrbildschirmsteuerungen
- So fügen Sie einen erweiterten Controller hinzu.
- So erstellst du ein einführendes Overlay.
- So passen Sie Cast-Widgets an.
- Cast Connect einbinden
Voraussetzungen
- Das neueste Android SDK
- Android Studio Version 3.2 oder höher
- Ein Mobilgerät mit Android 4.1 oder höher (Jelly Bean, API-Level 16)
- Ein USB-Datenkabel, um Ihr Mobilgerät mit Ihrem Entwicklungscomputer zu verbinden.
- Ein Google Cast-Gerät wie Chromecast oder Android TV mit Internetverbindung
- Einen Fernseher oder Monitor mit HDMI-Eingang
- Für den Test der Cast Connect-Integration ist Chromecast mit Google TV erforderlich, für den Rest des Codelabs ist es optional. Falls Sie keines haben, überspringen Sie den Schritt Cast Connect-Unterstützung hinzufügen gegen Ende dieser Anleitung.
Erfahrung
- Sie benötigen Vorkenntnisse in Kotlin und Android-Entwicklung.
- Außerdem solltest du schon einmal ferngesehen haben.
Wie möchten Sie diese Anleitung verwenden?
Wie würdest du deine Erfahrung mit der Entwicklung von Android-Apps bewerten?
Wie würden Sie Ihre Erfahrungen mit 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 an, wie die fertige Beispiel-App aussieht. 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 Sie den Code heruntergeladen haben, können Sie die fertige Beispiel-App in Android Studio öffnen und ausführen. Gehen Sie dazu so vor:
Wählen Sie auf dem Begrüßungsbildschirm Projekt importieren oder im Menü Datei > Neu > Projekt importieren… aus.
Wählen Sie im Ordner mit dem Beispielcode das Verzeichnis app-done
aus und klicken Sie auf „OK“.
Klicken Sie auf Datei > Projekt mit Gradle-Dateien synchronisieren.
Aktivieren Sie das USB-Debugging auf Ihrem Android-Gerät. Bei Android 4.2 und höher ist der Bildschirm „Entwickleroptionen“ standardmäßig ausgeblendet. Unter Einstellungen > Über das Telefon und tippen Sie siebenmal auf Build-Nummer. Kehren Sie zum vorherigen Bildschirm zurück, gehen Sie zu System > Erweitert und tippen Sie unten auf Entwickleroptionen. Aktivieren Sie dann USB-Debugging.
Schließen Sie Ihr Android-Gerät an die Stromversorgung an und klicken Sie in Android Studio auf die Schaltfläche Ausführen. Nach einigen Sekunden sollte die Video-App Videos streamen angezeigt werden.
Klicke in der Video-App auf die Schaltfläche „Streamen“ und wähle dein Google Cast-Gerät aus.
Wähle ein Video aus und klicke auf die Wiedergabeschaltfläche.
Die Wiedergabe des Videos beginnt auf Ihrem Google Cast-Gerät.
Der maximierte Controller wird angezeigt. Mit der Wiedergabe-/Pausetaste kannst du die Wiedergabe steuern.
Kehren Sie zur Liste der Videos zurück.
Unten auf dem Bildschirm wird jetzt ein Mini-Controller angezeigt.
Klicke auf die Pause-Schaltfläche auf der Minifernbedienung, um das Video auf dem Receiver anzuhalten. Klicke im Mini-Controller auf die Wiedergabeschaltfläche, um die Wiedergabe des Videos fortzusetzen.
Klicken Sie auf die Schaltfläche für die Startseite des Mobilgeräts. Wischen Sie nach unten zu den Benachrichtigungen. Jetzt sollte eine Benachrichtigung für die Übertragungssitzung angezeigt werden.
Sperren Sie Ihr Smartphone. Wenn Sie es entsperren, sollte auf dem Sperrbildschirm eine Benachrichtigung angezeigt werden, über die Sie die Medienwiedergabe steuern oder das Streamen beenden können.
Kehren Sie zur Video-App zurück und klicken Sie auf die Schaltfläche „Streamen“, um das Streaming auf dem Google Cast-Gerät zu beenden.
Häufig gestellte Fragen
4. Startprojekt vorbereiten
Wir müssen der von Ihnen heruntergeladenen Start-App Google Cast hinzufügen. Hier sind einige Google Cast-Begriffe, die wir in diesem Codelab verwenden werden:
- eine Sender-App auf einem Mobilgerät oder Laptop ausgeführt wird,
- Eine Receiver-App wird auf dem Google Cast-Gerät ausgeführt.
Jetzt können Sie mit Android Studio auf dem Starterprojekt aufbauen:
- Wählen Sie das Verzeichnis
app-start
aus dem heruntergeladenen Beispielcode aus. Wählen Sie dazu auf dem Begrüßungsbildschirm Import Project (Projekt importieren) oder die Menüoption File > New > Import Project... (Datei > Neu > Projekt importieren…) aus. - Klicken Sie auf die Schaltfläche
Projekt mit Gradle-Dateien synchronisieren.
- Klicken Sie auf die Schaltfläche
Ausführen, um die App auszuführen und die Benutzeroberfläche zu erkunden.
App-Design
Die App ruft eine Liste mit Videos von einem Remote-Webserver ab und stellt eine Liste für den Nutzer zum Stöbern bereit. Nutzer können ein Video auswählen, um die Details aufzurufen, oder das Video lokal auf einem Mobilgerät abspielen.
Die App besteht aus zwei Hauptaktivitäten: VideoBrowserActivity
und LocalPlayerActivity
. Damit die Google Cast-Funktion integriert werden kann, müssen die Aktivitäten entweder von der AppCompatActivity
oder vom übergeordneten Element FragmentActivity
übernommen werden. Diese Einschränkung besteht, da wir das MediaRouteButton
, das in der MediaRouter-Supportbibliothek bereitgestellt ist, als MediaRouteActionProvider
hinzufügen müssen. Dies funktioniert nur, wenn die Aktivität von den oben genannten Klassen übernommen wird. Die MediaRouter-Supportbibliothek ist von der AppCompat-Supportbibliothek abhängig, die die erforderlichen Klassen bereitstellt.
VideoBrowserActivity
Diese Aktivität enthält eine Fragment
(VideoBrowserFragment
). Diese Liste wird von einer ArrayAdapter
(VideoListAdapter
) unterstützt. Die Liste der Videos und die zugehörigen Metadaten werden auf einem Remote-Server als JSON-Datei gehostet. Ein AsyncTaskLoader
(VideoItemLoader
) ruft dieses JSON ab und verarbeitet es, um eine Liste von MediaItem
-Objekten zu erstellen.
Ein MediaItem
-Objekt stellt ein Video und die zugehörigen Metadaten dar, z. B. Titel, Beschreibung, URL für den Stream, URL für die unterstützenden Bilder und zugehörige Texttracks (für Untertitel). Das MediaItem
-Objekt wird zwischen Aktivitäten übergeben. MediaItem
verfügt also über Dienstprogrammmethoden, mit denen es in ein Bundle
-Objekt konvertiert werden kann und umgekehrt.
Wenn der Lader die Liste der MediaItems
erstellt, übergibt er diese Liste an den VideoListAdapter
, der die MediaItems
-Liste dann im VideoBrowserFragment
anzeigt. Der Nutzer sieht eine Liste mit Video-Thumbnails und einer kurzen Beschreibung für jedes Video. Wenn ein Element ausgewählt wird, wird die entsprechende MediaItem
in ein Bundle
konvertiert und an LocalPlayerActivity
übergeben.
LocalPlayerActivity
Bei dieser Aktivität werden die Metadaten zu einem bestimmten Video angezeigt und der Nutzer kann das Video lokal auf einem Mobilgerät abspielen.
Die Aktivität enthält ein VideoView
, einige Mediensteuerelemente und ein Textfeld, in dem die Beschreibung des ausgewählten Videos angezeigt wird. Der Player deckt den oberen Teil des Bildschirms ab und lässt darunter Platz für die detaillierte Videobeschreibung. Der Nutzer kann Videos abspielen/pausieren oder zur lokalen Wiedergabe von Videos spulen.
Abhängigkeiten
Da wir AppCompatActivity
verwenden, benötigen wir die AppCompat-Unterstützungsbibliothek. Um die Liste der Videos zu verwalten und die Bilder für die Liste asynchron abzurufen, verwenden wir die Volley-Bibliothek.
Häufig gestellte Fragen
5. Cast-Symbol hinzufügen
Auf einer für Google Cast optimierten App wird das Cast-Symbol bei jeder Aktivität angezeigt. Wenn du auf die Schaltfläche „Streamen“ klickst, wird eine Liste der Übertragungsgeräte angezeigt, die du auswählen kannst. Wenn der Nutzer Inhalte lokal auf dem Sendergerät abspielte, wird durch die Auswahl eines Übertragungsgeräts die Wiedergabe auf diesem Gerät gestartet oder fortgesetzt. Während einer Übertragung kann der Nutzer jederzeit auf die Schaltfläche „Streamen“ klicken und die Übertragung Ihrer Anwendung auf das Cast-Gerät beenden. Der Nutzer muss die Möglichkeit haben, sich mit dem Übertragungsgerät zu verbinden bzw. die Verbindung zu trennen, während er Ihre App verwendet. Weitere Informationen hierzu finden Sie in der Checkliste für das Google Cast-Design.
Abhängigkeiten
Aktualisieren Sie die build.gradle-Datei der App, um die erforderlichen Bibliotheksabhängigkeiten einzuschließen:
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 die Projekt-Builds fehlerfrei sind.
Initialisierung
Das Cast-Framework hat ein globales Singleton-Objekt, das CastContext
, das alle Cast-Interaktionen koordiniert.
Du musst die OptionsProvider
-Schnittstelle implementieren, um CastOptions
anzugeben, das zum Initialisieren des CastContext
-Singleton-Elements erforderlich ist. Die wichtigste Option ist die ID der Empfänger-App. Sie wird verwendet, um die Ergebnisse der Übertragungsgeräteerkennung zu filtern und die Empfänger-App zu starten, wenn eine Übertragung gestartet wird.
Wenn Sie Ihre eigene für Google Cast optimierte App entwickeln, müssen Sie sich als Cast-Entwickler registrieren und dann eine Anwendungs-ID für Ihre App abrufen. In diesem 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
}
}
Deklarieren Sie jetzt das OptionsProvider
in „application
“ Tag der App-Datei AndroidManifest.xml
:
<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
verzögert in 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
dieselbe Initialisierungslogik hinzu.
Cast-Symbol
Nachdem CastContext
initialisiert wurde, muss das Cast-Symbol hinzugefügt werden, damit der Nutzer ein Übertragungsgerät auswählen kann. Das Cast-Symbol wird vom MediaRouteButton
aus der MediaRouter-Supportbibliothek implementiert. Wie bei allen Aktionssymbolen, die Sie Ihrer Aktivität hinzufügen können (entweder mit ActionBar
oder Toolbar
), müssen Sie zuerst den entsprechenden Menüpunkt hinzufügen.
Bearbeiten Sie die Datei res/menu/browse.xml
und fügen Sie den Menüpunkt MediaRouteActionProvider
vor dem Menüpunkt „Einstellungen“ ein:
<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 onCreateOptionsMenu()
-Methode von VideoBrowserActivity
, indem Sie CastButtonFactory
verwenden, um die 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 die Schaltfläche „Streamen“ angezeigt werden. Wenn Sie darauf klicken, werden die Cast-Geräte in Ihrem lokalen Netzwerk aufgelistet. Die Geräteerkennung wird automatisch vom
CastContext
verwaltet. Wählen Sie Ihr Übertragungsgerät aus. Die Beispiel-Empfänger-App wird auf dem Übertragungsgerät geladen. Sie können zwischen den Browseraktivitäten und den Aktivitäten des lokalen Players wechseln. Der Status der Schaltfläche „Streamen“ wird dabei synchronisiert.
Die Medienwiedergabe wird noch nicht unterstützt. Du kannst also noch keine Videos auf dem Streaminggerät abspielen. Klicken Sie auf das Cast-Symbol, um die Verbindung zu trennen.
6. Videoinhalte streamen
Wir werden die Beispiel-App so erweitern, dass Videos auch per Fernzugriff auf einem Cast-Gerät wiedergegeben werden können. Dazu müssen wir die verschiedenen vom Cast-Framework generierten Ereignisse überwachen.
Medien streamen
Wenn Sie Medien auf einem Streaminggerät wiedergeben möchten, müssen Sie im Wesentlichen Folgendes tun:
- Erstellen Sie ein
MediaInfo
-Objekt, das ein Medienelement modelliert. - Stelle eine Verbindung zum Streaminggerät her und starte die Empfängeranwendung.
- Laden Sie das
MediaInfo
-Objekt in den Receiver und spielen Sie den Inhalt ab. - Beobachten Sie den Medienstatus.
- Senden Sie Wiedergabebefehle an den Empfänger basierend auf Nutzerinteraktionen.
Schritt 2 im vorherigen Abschnitt wurde bereits ausgeführt. Schritt 3 ist mit dem Cast-Framework ganz einfach. In Schritt 1 ordnen wir ein Objekt einem anderen zu. MediaInfo
ist ein Objekt, das vom Cast-Framework verstanden wird, und MediaItem
ist die Kapselung eines Medienelements in unserer App. Wir können MediaItem
ganz einfach einem MediaInfo
zuordnen.
In der Beispiel-App LocalPlayerActivity
wird bereits anhand dieses Enumerationstyps zwischen lokaler und Remote-Wiedergabe unterschieden:
private var mLocation: PlaybackLocation? = null
enum class PlaybackLocation {
LOCAL, REMOTE
}
enum class PlaybackState {
PLAYING, PAUSED, BUFFERING, IDLE
}
In diesem Codelab ist es nicht wichtig, zu verstehen, wie die gesamte Beispiellogik von Playern funktioniert. Der Mediaplayer Ihrer App muss so angepasst werden, dass er die beiden Wiedergabeorte auf ähnliche Weise erkennt.
Derzeit befindet sich der lokale Player immer im Status der lokalen Wiedergabe, da er noch nichts über die Streamingstatus weiß. Wir müssen die Benutzeroberfläche basierend auf Statusübergängen im Cast-Framework aktualisieren. Wenn wir beispielsweise mit dem Streamen beginnen, müssen wir die lokale Wiedergabe beenden und einige Steuerelemente deaktivieren. Wenn wir das Streaming in dieser Aktivität beenden, müssen wir zur lokalen Wiedergabe wechseln. Dazu müssen wir auf die verschiedenen Ereignisse warten, die vom Cast-Framework generiert werden.
Streamingsitzung verwalten
Beim Cast-Framework umfasst eine Cast-Sitzung die Schritte: Verbinden mit einem Gerät, Starten oder Teilnehmen, Herstellen einer Verbindung zu einer Empfänger-App und Initialisieren eines Mediensteuerungskanals, falls erforderlich. Über den Mediensteuerungskanal sendet und empfängt das Cast-Framework Nachrichten vom Empfänger-Mediaplayer.
Das Streamen wird automatisch gestartet, wenn der Nutzer ein Gerät über das Cast-Symbol auswählt, und automatisch beendet, wenn der Nutzer die Verbindung trennt. Die automatische Wiederverbindung mit einer Empfängersitzung aufgrund von Netzwerkproblemen wird ebenfalls vom Cast SDK verwaltet.
Fügen wir der LocalPlayerActivity
eine 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 der Aktivität LocalPlayerActivity
möchten wir wissen, wenn eine Verbindung zum oder eine Trennung vom Streaminggerät hergestellt wird, damit wir zum lokalen Player wechseln können. Die Verbindung kann nicht nur durch die Instanz Ihrer Anwendung auf Ihrem Mobilgerät unterbrochen werden, sondern auch durch eine andere Instanz Ihrer (oder einer anderen) Anwendung, die auf einem anderen Mobilgerät ausgeführt wird.
Die derzeit aktive Sitzung kann als SessionManager.getCurrentSession()
aufgerufen werden. Sitzungen werden automatisch erstellt und beendet, wenn Nutzer mit den Übertragungsdialogen interagieren.
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 die RemoteMediaClient
eine Reihe praktischer APIs zur Verwaltung der Remote-Medienwiedergabe auf dem Empfänger. Für eine CastSession
, die die Medienwiedergabe unterstützt, wird vom SDK automatisch eine Instanz von RemoteMediaClient
erstellt. Sie können darauf zugreifen, indem Sie die getRemoteMediaClient()
-Methode auf der CastSession
-Instanz aufrufen. Füge LocalPlayerActivity
die folgenden Methoden 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()
}
}
Aktualisiere jetzt verschiedene vorhandene Methoden, um die Cast-Sitzungslogik zur Unterstützung der 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 die Schaltfläche Ausführen, um die App auf Ihrem Mobilgerät auszuführen. Stellen Sie eine Verbindung zu Ihrem Übertragungsgerät her und starten Sie die Wiedergabe eines Videos. Das Video sollte auf dem Receiver wiedergegeben werden.
7. Mini-Controller
Gemäß der Checkliste für das Cast-Design müssen alle Cast-Apps einen Mini-Controller haben, der angezeigt wird, wenn der Nutzer die aktuelle Inhaltsseite verlässt. Der Mini-Controller bietet sofortigen Zugriff und eine sichtbare Erinnerung an die aktuelle Übertragungssitzung.
Das Cast SDK bietet eine benutzerdefinierte Ansicht, MiniControllerFragment
, die der App-Layoutdatei der Aktivitäten hinzugefügt werden kann, in denen der Mini-Controller angezeigt werden soll.
Fügen Sie die folgende Fragmentdefinition unten in res/layout/player_activity.xml
und res/layout/video_browser.xml
hinzu:
<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 bei jeder Aktivität der Mini-Controller angezeigt werden. Sie können die Wiedergabe über den Mini-Controller steuern. Wenn Sie zwischen der Suchaktivität und der Aktivität des lokalen Players wechseln, sollte der Mini-Controller-Status mit dem Medienwiedergabestatus des Empfängers synchron bleiben.
8. Benachrichtigungen und Sperrbildschirm
Gemäß der Design-Checkliste für Google Cast muss eine Absender-App Mediensteuerelemente über eine Benachrichtigung und den Sperrbildschirm implementieren.
Das Cast SDK bietet eine MediaNotificationService
, mit der die Absender-App Mediensteuerelemente für Benachrichtigungen und Sperrbildschirm erstellen kann. Der Dienst wird von Gradle automatisch in das Manifest Ihrer App eingefügt.
MediaNotificationService
wird während des Streamings durch den Absender im Hintergrund ausgeführt und zeigt eine Benachrichtigung mit einer Miniaturansicht und den Metadaten des gestreamten Elements sowie eine Schaltfläche für Wiedergabe/Pause und eine Stopp-Schaltfläche an.
Die Steuerelemente für Benachrichtigungen und den Sperrbildschirm können mit dem CastOptions
bei der Initialisierung von CastContext
aktiviert werden. Die Mediensteuerung für Benachrichtigungen und Sperrbildschirm sind standardmäßig aktiviert. Die Funktion „Sperrbildschirm“ ist aktiviert, solange Benachrichtigungen aktiviert sind.
Bearbeiten Sie CastOptionsProvider
und ändern Sie die getCastOptions
-Implementierung so, dass sie mit diesem Code übereinstimmt:
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 geben, das gerade auf dem Empfänger wiedergegeben wird. Sperren Sie Ihr Mobilgerät. Auf dem Sperrbildschirm sollten jetzt Steuerelemente für die Medienwiedergabe auf dem Übertragungsgerät angezeigt werden.
9. Einführungs-Overlay
Gemäß der Google Cast-Design-Checkliste muss eine Sender-App bestehenden Nutzern die Schaltfläche „Streamen“ präsentieren, um sie darüber zu informieren, dass die Sender-App jetzt das Streamen unterstützt. Außerdem sollte sie Nutzern, die Google Cast noch nicht kennen, helfen.
Das Cast SDK bietet eine benutzerdefinierte Ansicht (IntroductoryOverlay
), mit der das Cast-Symbol hervorgehoben werden kann, 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 eine CastStateListener
hinzu und rufen Sie die Methode showIntroductoryOverlay
auf, wenn ein Streaminggerät verfügbar ist. Ändern Sie dazu die Methode onCreate
und überschreiben Sie die Methoden onResume
und onPause
so, dass sie den folgenden Anforderungen entsprechen:
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ösche die App-Daten oder entferne die App von deinem Gerät. Klicken Sie dann auf die Schaltfläche Ausführen, um die App auf Ihrem Mobilgerät auszuführen. Daraufhin sollte das einführende Overlay zu sehen sein. Löschen Sie die App-Daten, wenn das Overlay nicht angezeigt wird.
10. Maximierter Controller
Gemäß der Checkliste für das Design von Google Cast muss eine Sender-App einen erweiterten Controller für die gestreamten Medien bereitstellen. Der erweiterte Controller ist eine Vollbildversion des Mini-Controllers.
Das Cast SDK bietet ein Widget für den erweiterten Controller namens ExpandedControllerActivity
. Dies ist eine abstrakte Klasse, deren Klasse Sie ableiten müssen, um ein Cast-Symbol hinzuzufügen.
Erstellen Sie zuerst eine neue Menüressourcendatei namens expanded_controller.xml
für den erweiterten Controller, um die Schaltfläche „Streamen“ 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 Paket expandedcontrols
im Paket com.google.sample.cast.refplayer
. Erstellen Sie als Nächstes im Paket com.google.sample.cast.refplayer.expandedcontrols
eine neue Datei mit dem Namen ExpandedControlsActivity.kt
.
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
}
}
Deklarieren Sie nun die ExpandedControlsActivity
im AndroidManifest.xml
innerhalb des application
-Tags über der 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 die CastOptionsProvider
und ändern Sie NotificationOptions
und CastMediaOptions
, um die Zielaktivität auf die 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 Methode LocalPlayerActivity
loadRemoteMedia
, damit ExpandedControlsActivity
angezeigt wird, wenn die Remote-Medien geladen werden:
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. Wenn du zur Videoliste zurückkehrst und auf den Mini-Controller klickst, wird der maximierte Controller wieder geladen. Verlassen Sie die App, um die Benachrichtigung zu sehen. Klicken Sie auf das Benachrichtigungsbild, um den erweiterten Controller zu laden.
11. Cast Connect-Unterstützung hinzufügen
Mithilfe der Cast Connect-Bibliothek können bestehende Absender-Apps über das Cast-Protokoll mit Android TV-Apps kommunizieren. Cast Connect baut auf der Cast-Infrastruktur auf, wobei deine Android TV-App als Receiver fungiert.
Abhängigkeiten
Hinweis: Zur Implementierung von Cast Connect muss play-services-cast-framework
mindestens 19.0.0
sein.
LaunchOptions
Damit die Android TV-Anwendung, auch als Android-Empfänger bezeichnet, gestartet werden kann, müssen wir das Flag setAndroidReceiverCompatible
im Objekt LaunchOptions
auf „true“ setzen. Dieses LaunchOptions
-Objekt legt fest, wie der Empfänger gestartet wird, und wird an den CastOptions
übergeben, der von der CastOptionsProvider
-Klasse zurückgegeben wird. Wenn du das oben genannte Flag auf false
setzt, wird der Webempfänger für die definierte App-ID in der Cast Developer Console gestartet.
Fügen Sie in der Datei CastOptionsProvider.kt
der Methode getCastOptions
Folgendes 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 den Start festlegen
Auf der Absenderseite können Sie CredentialsData
angeben, um anzugeben, wer an der Sitzung teilnimmt. credentials
ist ein String, der vom Nutzer definiert werden kann, solange er von deiner ATV-App verstanden wird. Die CredentialsData
wird nur während des Starts oder der Teilnahme an deiner Android TV App übergeben. Wenn Sie die Einstellung neu festlegen, während eine Verbindung besteht, wird sie nicht an Ihre Android TV App übergeben.
Zum Festlegen von Startanmeldedaten muss CredentialsData
definiert und an das LaunchOptions
-Objekt übergeben werden. Fügen Sie der Methode 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
Falls die Web Receiver App und die Android TV App credentials
unterschiedlich verarbeiten, musst du möglicherweise für jeden ein separates credentials
-Objekt definieren. Fügen Sie dazu in 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 nach Empfänger-App, auf die der Sender streamt, wählt das SDK jetzt automatisch die Anmeldedaten für die aktuelle Sitzung aus.
Cast Connect wird getestet
Schritte zur Installation des Android TV APK auf Chromecast mit Google TV
- Ermitteln Sie die IP-Adresse Ihres Android TV-Geräts. Normalerweise befindet sich die Option unter Einstellungen > Netzwerk und Internet > (Netzwerkname, mit dem Ihr Gerät verbunden ist). Auf der rechten Seite werden die Details und die IP-Adresse Ihres Geräts im Netzwerk angezeigt.
- Verwenden Sie die IP-Adresse Ihres Geräts, um über das Terminal eine ADB-Verbindung 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-Gerät:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Sie sollten jetzt auf Ihrem Android TV-Gerät im Menü Meine Apps eine App mit dem Namen Videos streamen finden.
- Kehren Sie zu Ihrem Android Studio-Projekt zurück und klicken Sie auf die Schaltfläche „Ausführen“, um die Sender-App auf Ihrem physischen Mobilgerät zu installieren und auszuführen. Klicken Sie rechts oben auf das Cast-Symbol und wählen Sie aus den verfügbaren Optionen Ihr Android TV-Gerät aus. Die Android TV App sollte jetzt auf Ihrem Android TV-Gerät gestartet werden. Abspielen eines Videos sollte es Ihnen möglich sein, die Videowiedergabe mithilfe der Android TV-Fernbedienung zu steuern.
12. Streaming-Widgets anpassen
Sie können Streaming-Widgets anpassen, indem Sie die Farben festlegen, die Schaltflächen, den Text und das Thumbnail gestalten und die angezeigten Schaltflächentypen auswählen.
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>
Deklarieren Sie die folgenden benutzerdefinierten Designs:
<!-- 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 mithilfe der Cast SDK-Widgets für Android eine Video-App für Google Cast aktivieren.
Weitere Informationen finden Sie im Android Sender-Entwicklerleitfaden.