Android-App für Google Cast aktivieren

1. Übersicht

Google Cast-Logo

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?

Nur Lesen Lesen und lesen

Wie würden Sie Ihre Erfahrungen im Entwickeln von Android-Apps bewerten?

Neuling Leicht fortgeschrittener Profi

Wie würdest du deine Erfahrung beim Fernsehen bewerten?

Neuling Fortgeschrittener Anfänger Profi

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

Symbol von zwei Kompassen

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 Ordnersymbolapp-done aus dem Beispielcodeordner aus und klicken Sie auf „OK“.

Klicken Sie auf Datei > Schaltfläche „Projekt mit Gradle synchronisieren“ in Android Studio 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 Die Schaltfläche „Run“ in Android Studio, ein grünes Dreieck, das nach rechts zeigtAusfü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. Abbildung eines Android-Smartphones, auf dem die App „Videos streamen“ ausgeführt wird. Der Mini-Controller wird unten auf dem Bildschirm angezeigt.

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

Abbildung eines Android-Smartphones, auf dem die App „Videos streamen“ ausgeführt wird

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:

  1. Wählen Sie das Verzeichnis Ordnersymbolapp-start aus dem Beispielcode aus (wählen Sie auf der Begrüßungsseite Projekt importieren oder die Menüoption Datei > Neu > Projekt importieren...).
  2. Klicken Sie auf die Schaltfläche Schaltfläche „Projekt mit Gradle synchronisieren“ in Android Studio Sync Project with Gradle Files (Projekt mit Gradle-Dateien synchronisieren).
  3. Klicken Sie auf die Schaltfläche Die Schaltfläche „Run“ in Android Studio, ein grünes Dreieck, das nach rechts zeigtAusfü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

Abbildung des oberen Teils eines Android-Smartphones, auf dem die Cast Video App ausgeführt wird. Das Cast-Symbol wird oben rechts auf dem Bildschirm angezeigt.

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 Die Schaltfläche „Run“ in Android Studio, ein grünes Dreieck, das nach rechts zeigtAusfü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

Abbildung eines Android-Smartphones, auf dem die App „Videos streamen“ ausgeführt wird

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:

  1. Erstellen Sie ein MediaInfo-Objekt, mit dem ein Medienelement modelliert wird.
  2. Stellen Sie eine Verbindung zum Übertragungsgerät her und starten Sie die Empfängeranwendung.
  3. Laden Sie das MediaInfo-Objekt in den Receiver und spielen Sie den Inhalt ab.
  4. Medienstatus verfolgen
  5. 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 Die Schaltfläche „Run“ in Android Studio, ein grünes Dreieck, das nach rechts zeigtAusfü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.

Illustration des unteren Teils eines Android-Smartphones, auf dem der Miniplayer in der App „Videos streamen“ zu sehen ist

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 Die Schaltfläche „Run“ in Android Studio, ein grünes Dreieck, das nach rechts zeigtAusfü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.

Abbildung eines Android-Smartphones mit Mediensteuerelementen im Benachrichtigungsbereich

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 Die Schaltfläche „Run“ in Android Studio, ein grünes Dreieck, das nach rechts zeigtAusfü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.

Abbildung eines Android-Smartphones mit Mediensteuerelementen auf dem Sperrbildschirm

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.

Abbildung mit dem Cast-Overlay, das um das Cast-Symbol in der Android-App „Cast-Videos“ angezeigt wird

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 Die Schaltfläche „Run“ in Android Studio, ein grünes Dreieck, das nach rechts zeigtAusfü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.

Abbildung eines Videos, das auf einem Android-Smartphone abgespielt wird, auf dem der Controller maximiert ist

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 Die Schaltfläche „Run“ in Android Studio, ein grünes Dreieck, das nach rechts zeigtAusfü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

  1. 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.
  2. 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
  1. 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
  1. Installieren Sie die APK-Datei in diesem Ordner auf Ihrem Android TV:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. Auf Ihrem Android TV-Gerät sollte jetzt im Menü Meine Apps eine App mit dem Namen Videos streamen zu sehen sein.
  2. 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.