1) Übersicht
In diesem Codelab erfahren Sie, wie Sie eine vorhandene iOS-Video-App so ändern, dass Inhalte auf ein für Google Cast optimiertes Gerät gestreamt werden.
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 und so Google Cast-fähige Geräte wie einen Fernseher oder ein Soundsystem steuern. Mit dem Cast SDK können Sie basierend auf der Checkliste für das Google Cast-Design die erforderlichen UI-Komponenten hinzufügen.
Die Google Cast Design-Checkliste soll Nutzern die Arbeit mit allen unterstützten Plattformen erleichtern.
Ziele
Wenn Sie dieses Codelab abgeschlossen haben, haben Sie eine iOS-Video-App, mit der Sie Videos auf ein Google Cast-Gerät streamen können.
Lerninhalte
- Das Google Cast SDK einer Beispiel-Video-App hinzufügen
- Wie Sie das Cast-Symbol hinzufügen, um ein Google Cast-Gerät auszuwählen.
- Verbindung zu einem Übertragungsgerät herstellen und einen Medienempfänger starten
- Ein Video streamen
- So fügen Sie Ihrer App einen Mini-Cast hinzu
- Erweiterten Controller hinzufügen
- Einführendes Overlay bereitstellen
- Cast-Widgets anpassen
- Cast Connect einbinden
Voraussetzungen
- Die neueste Version des Xcode.
- Ein Mobilgerät mit iOS 9 oder höher oder mit dem Xcode-Simulator.
- Ein USB-Datenkabel zum Verbinden Ihres Mobilgeräts mit Ihrem Entwicklungscomputer (falls ein Gerät verwendet wird).
- Ein Google Cast-Gerät wie ein Chromecast oder Android TV, das mit dem Internet verbunden ist.
- Ein Fernseher oder Monitor mit HDMI-Eingang.
- Für das Testen der Einbindung von Cast Connect ist Chromecast mit Google TV erforderlich. Für den Rest des Codelabs ist das optional. Wenn Sie keine haben, können Sie den Schritt Cast Connect-Support hinzufügen am Ende dieser Anleitung überspringen.
Plattform
- Sie benötigen Vorkenntnisse zu iOS-Entwicklungen.
- Außerdem brauchst du Erfahrung mit dem Fernsehen.
Wie werden Sie dieses Tutorial verwenden?
Wie würden Sie Ihre Erfahrungen mit der Entwicklung von iOS-Apps bewerten?
Wie würdest du deine Erfahrung mit dem Fernsehen bewerten?
2. Beispielcode abrufen
Sie können entweder 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 abspielen oder auf ein Google Cast-Gerät streamen.
Nachdem der Code heruntergeladen wurde, wird in der folgenden Anleitung beschrieben, wie Sie die fertige Beispiel-App in Xcode öffnen und ausführen:
Häufig gestellte Fragen
CocoaPods-Einrichtung
Rufen Sie zum Einrichten von CocoaPods die Konsole auf und installieren Sie sie mit dem standardmäßig unter macOS verfügbaren Ruby-Code:
sudo gem install cocoapods
Sollten Probleme auftreten, lesen Sie die offizielle Dokumentation und laden Sie den Abhängigkeits-Manager herunter und installieren Sie ihn.
Projekt einrichten
- Öffnen Sie in Ihrem Terminal das Codelab-Verzeichnis.
- Installieren Sie die Abhängigkeiten aus der Podfile.
cd app-done pod update pod install
- Öffnen Sie Xcode und wählen Sie Anderes Projekt öffnen... aus.
- Wählen Sie im Verzeichnis des Beispielcodes die Datei
CastVideos-ios.xcworkspace
aus dem Verzeichnisapp-done
aus.
Anwendung ausführen
Wählen Sie das Ziel und den Simulator aus und führen Sie die App aus:
Die Video-App sollte nach einigen Sekunden angezeigt werden.
Klicken Sie auf „Zulassen“, wenn die Benachrichtigung über die Annahme eingehender Netzwerkverbindungen angezeigt wird. Das Cast-Symbol wird nicht angezeigt, wenn diese Option nicht akzeptiert wird.
Klicken Sie 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 erweiterte Controller wird angezeigt. Mit der Schaltfläche für Wiedergabe/Pause kannst du die Wiedergabe steuern.
Zurück zur Videoliste.
Unten auf dem Bildschirm wird jetzt ein Mini-Controller angezeigt.
Klicke auf die Pause-Taste im Mini-Controller, um das Video auf dem Empfänger zu pausieren. Klicke auf die Wiedergabeschaltfläche im Mini-Controller, um die Wiedergabe des Videos fortzusetzen.
Klicke auf das Cast-Symbol, um die Übertragung auf das Google Cast-Gerät zu beenden.
4. Startprojekt vorbereiten
Wir benötigen Unterstützung für Google Cast in der heruntergeladenen Start-App. Die folgenden Google Cast-Begriffe werden in diesem Codelab verwendet:
- eine Absender-App auf einem Mobilgerät oder Laptop ausgeführt wird und
- Eine Empfänger-App wird auf dem Google Cast-Gerät ausgeführt.
Projekt einrichten
Jetzt können Sie auf dem Startprojekt mit Xcode aufbauen:
- Öffnen Sie in Ihrem Terminal das Codelab-Verzeichnis.
- Installieren Sie die Abhängigkeiten aus der Podfile.
cd app-start pod update pod install
- Öffnen Sie Xcode und wählen Sie Anderes Projekt öffnen... aus.
- Wählen Sie im Verzeichnis des Beispielcodes die Datei
CastVideos-ios.xcworkspace
aus dem Verzeichnisapp-start
aus.
App-Design
Die App ruft eine Liste der Videos von einem Remote-Webserver ab und stellt dem Nutzer eine Liste mit diesen 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 Controllern für die Hauptansicht: MediaTableViewController
und MediaViewController.
.
MediaTableViewController
Mit diesem UITableViewController wird eine Liste der Videos aus einer MediaListModel
-Instanz angezeigt. Die Liste der Videos und die zugehörigen Metadaten werden als JSON-Datei auf einem Remoteserver gehostet. MediaListModel
ruft dieses JSON-Objekt ab und verarbeitet es, um eine Liste mit MediaItem
-Objekten zu erstellen.
Ein MediaItem
-Objekt modelliert ein Video und die zugehörigen Metadaten, beispielsweise Titel, Beschreibung, URL für ein Bild und URL für den Stream.
MediaTableViewController
erstellt eine MediaListModel
-Instanz und registriert sich dann als MediaListModelDelegate
, um informiert zu werden, wenn die Medienmetadaten heruntergeladen wurden, um die Tabellenansicht zu laden.
Dem Nutzer wird eine Liste mit Video-Thumbnails mit einer kurzen Beschreibung für jedes Video angezeigt. Wenn ein Element ausgewählt wird, wird der entsprechende MediaItem
an MediaViewController
übergeben.
MediaViewController
Dieser Ansichts-Controller zeigt die Metadaten zu einem bestimmten Video an und ermöglicht dem Nutzer, das Video lokal auf dem Mobilgerät abzuspielen.
Der Ansichts-Controller hostet eine LocalPlayerView
, einige Mediensteuerelemente und einen Textbereich, um die Beschreibung des ausgewählten Videos anzuzeigen. Der Player verdeckt den oberen Teil des Bildschirms. So bleibt Platz für eine detaillierte Beschreibung des Videos unter dem Nutzer. Der Nutzer kann die lokale Videowiedergabe starten, pausieren oder fortsetzen.
Häufig gestellte Fragen
5. Cast-Symbol hinzufügen
In einer für Google Cast optimierten App wird das Cast-Symbol in den einzelnen Controllern angezeigt. Wenn der Nutzer auf das Cast-Symbol klickt, wird eine Liste mit Übertragungsgeräten angezeigt, die der Nutzer auswählen kann. Wenn der Nutzer Inhalte lokal auf dem Absendergerät wiedergegeben hat, wird durch Auswahl eines Übertragungsgeräts die Wiedergabe auf diesem Übertragungsgerät gestartet oder fortgesetzt. Während des Streamings kann der Nutzer jederzeit auf das Cast-Symbol klicken und die Übertragung Ihrer App an das Übertragungsgerät beenden. Der Nutzer muss eine Verbindung zum Cast-Gerät herstellen bzw. trennen können, während die App auf einem beliebigen Bildschirm geöffnet wird. Dies wird in der Checkliste für das Google Cast-Design beschrieben.
Konfiguration
Für das Startprojekt müssen dieselben Abhängigkeiten und Xcode-Einrichtung wie für die abgeschlossene Beispiel-App verwendet werden. Kehren Sie zu diesem Abschnitt zurück und führen Sie dieselben Schritte aus, um GoogleCast.framework
zum Start-App-Projekt hinzuzufügen.
Initialisierung
Das Cast-Framework hat das globale Singleton-Objekt GCKCastContext
, das alle Aktivitäten des Frameworks koordiniert. Dieses Objekt muss frühzeitig im Lebenszyklus der Anwendung initialisiert werden. Dies ist normalerweise in der application(_:didFinishLaunchingWithOptions:)
-Methode des Anwendungsdelegats der Fall, sodass die automatische Sitzungswiederaufnahme beim Neustart der Absenderanwendung korrekt ausgelöst und das Scannen für Geräte gestartet werden kann.
Bei der Initialisierung von GCKCastContext
muss ein GCKCastOptions
-Objekt angegeben werden. Diese Klasse enthält Optionen, die sich auf das Verhalten des Frameworks auswirken. Am wichtigsten ist die ID der Receiver-Anwendung. Damit wird die Erkennung der Übertragungsgeräte gefiltert und die Empfängeranwendung gestartet, wenn eine Cast-Sitzung gestartet wird.
Die Methode application(_:didFinishLaunchingWithOptions:)
ist auch eine gute Möglichkeit, einen Logging-Bevollmächtigten einzurichten, um die Logging-Nachrichten vom Cast-Framework zu empfangen. Dies kann bei der Fehlerbehebung hilfreich sein.
Wenn Sie Ihre eigene Cast-fähige App entwickeln, müssen Sie sich als Cast-Entwickler registrieren und dann eine Anwendungs-ID für Ihre App abrufen. Für dieses Codelab verwenden wir eine Beispiel-App-ID.
Fügen Sie zu AppDelegate.swift
den folgenden Code hinzu, um GCKCastContext
mit der Anwendungs-ID aus den Standardeinstellungen des Nutzers zu initialisieren. Fügen Sie einen Logger für das Google Cast-Framework hinzu:
import GoogleCast
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
fileprivate var enableSDKLogging = true
...
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: kReceiverAppID))
options.physicalVolumeButtonsWillControlDeviceVolume = true
GCKCastContext.setSharedInstanceWith(options)
window?.clipsToBounds = true
setupCastLogging()
...
}
...
func setupCastLogging() {
let logFilter = GCKLoggerFilter()
let classesToLog = ["GCKDeviceScanner", "GCKDeviceProvider", "GCKDiscoveryManager", "GCKCastChannel",
"GCKMediaControlChannel", "GCKUICastButton", "GCKUIMediaController", "NSMutableDictionary"]
logFilter.setLoggingLevel(.verbose, forClasses: classesToLog)
GCKLogger.sharedInstance().filter = logFilter
GCKLogger.sharedInstance().delegate = self
}
}
...
// MARK: - GCKLoggerDelegate
extension AppDelegate: GCKLoggerDelegate {
func logMessage(_ message: String,
at _: GCKLoggerLevel,
fromFunction function: String,
location: String) {
if enableSDKLogging {
// Send SDK's log messages directly to the console.
print("\(location): \(function) - \(message)")
}
}
}
Cast-Symbol
Nachdem die GCKCastContext
initialisiert wurde, müssen wir das Cast-Symbol hinzufügen, damit der Nutzer ein Übertragungsgerät auswählen kann. Das Cast SDK umfasst eine Cast-Schaltflächenkomponente namens GCKUICastButton
als UIButton
-Unterklasse. Sie kann der Titelleiste der App hinzugefügt werden, indem Sie den Parameter in einen UIBarButtonItem
umschließen. Wir müssen das Cast-Symbol sowohl zu MediaTableViewController
als auch zu MediaViewController
hinzufügen.
Fügen Sie den folgenden Code in MediaTableViewController.swift
und MediaViewController.swift
ein:
import GoogleCast
@objc(MediaTableViewController)
class MediaTableViewController: UITableViewController, GCKSessionManagerListener,
MediaListModelDelegate, GCKRequestDelegate {
private var castButton: GCKUICastButton!
...
override func viewDidLoad() {
print("MediaTableViewController - viewDidLoad")
super.viewDidLoad()
...
castButton = GCKUICastButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0),
width: CGFloat(24), height: CGFloat(24)))
// Overwrite the UIAppearance theme in the AppDelegate.
castButton.tintColor = UIColor.white
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
...
}
...
}
Fügen Sie als Nächstes den folgenden Code in die Datei MediaViewController.swift
ein:
import GoogleCast
@objc(MediaViewController)
class MediaViewController: UIViewController, GCKSessionManagerListener, GCKRemoteMediaClientListener,
LocalPlayerViewDelegate, GCKRequestDelegate {
private var castButton: GCKUICastButton!
...
override func viewDidLoad() {
super.viewDidLoad()
print("in MediaViewController viewDidLoad")
...
castButton = GCKUICastButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0),
width: CGFloat(24), height: CGFloat(24)))
// Overwrite the UIAppearance theme in the AppDelegate.
castButton.tintColor = UIColor.white
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
...
}
...
}
Führen Sie die App jetzt aus. Wenn Sie in der Navigationsleiste der App auf ein Cast-Symbol klicken, wird eine Liste der Übertragungsgeräte in Ihrem lokalen Netzwerk angezeigt. Die Erkennung von Geräten wird automatisch von GCKCastContext
verwaltet. Wählen Sie Ihr Übertragungsgerät aus. Die Beispiel-Empfänger-App wird auf dem Übertragungsgerät geladen. Du kannst zwischen den Stöberaktivitäten und der lokalen Spieleraktivität wechseln, während der Cast-Symbolstatus synchronisiert wird.
Wir haben keine Unterstützung für die Medienwiedergabe festgelegt, sodass Sie noch keine Videos auf dem Übertragungsgerät abspielen können. Klicke auf das Cast-Symbol, um die Übertragung zu beenden.
6. Videoinhalte streamen
Die Beispiel-App wird erweitert, damit du auch Videos per Fernzugriff auf einem Übertragungsgerät abspielen kannst. Dazu müssen wir die verschiedenen Ereignisse beobachten, die vom Cast-Framework generiert werden.
Medien werden gestreamt
Wenn Sie Medien auf einem Übertragungsgerät abspielen möchten, müssen Sie folgende Voraussetzungen erfüllen:
- Erstellen Sie über das Cast SDK ein
GCKMediaInformation
-Objekt, das ein Medienelement modelliert. - Der Nutzer stellt eine Verbindung zum Übertragungsgerät her, um die Empfängeranwendung zu starten.
- Laden Sie das
GCKMediaInformation
-Objekt in den Receiver und spielen Sie den Inhalt ab. - Verfolgen Sie den Medienstatus.
- Sende basierend auf Nutzerinteraktionen Wiedergabebefehle an den Empfänger.
Im ersten Schritt wird ein Objekt einem anderen zugeordnet. GCKMediaInformation
ist etwas, das vom Cast SDK verstanden wird, und MediaItem
ist das Kapselsystem unserer App für ein Medienelement. Wir können ein MediaItem
ganz einfach einem GCKMediaInformation
zuordnen. Wir haben Schritt 2 bereits ausgeführt. Schritt 3 ist mit dem Cast SDK ganz einfach.
Die Beispiel-App MediaViewController
unterscheidet mithilfe der folgenden Aufzählung bereits zwischen lokaler und Remote-Wiedergabe:
enum PlaybackMode: Int {
case none = 0
case local
case remote
}
private var playbackMode = PlaybackMode.none
Es ist nicht wichtig, in diesem Codelab zu verstehen, wie die Beispiellogik funktioniert. Es ist wichtig zu verstehen, dass der Mediaplayer deiner App so verändert werden muss, dass die beiden Wiedergabeorte ähnlich erkannt werden.
Zurzeit befindet sich der lokale Player immer im lokalen Wiedergabestatus, da er noch nichts über den Streamingstatus weiß. Wir müssen die UI auf der Grundlage von Statusübergängen aktualisieren, die im Cast-Framework stattfinden. Wenn wir beispielsweise mit dem Streamen beginnen, müssen wir die lokale Wiedergabe beenden und einige Steuerelemente deaktivieren. Wenn wir das Streaming beenden, wenn wir uns in diesem Ansicht-Controller befinden, müssen wir zur lokalen Wiedergabe übergehen. Dazu müssen wir die verschiedenen Ereignisse überwachen, die vom Cast-Framework generiert werden.
Streamingsitzungen verwalten
Für das Cast-Framework werden bei Cast-Sitzungen die Schritte zum Verbinden mit einem Gerät, Starten (oder Beitreten) zum Verbinden mit einer Empfängeranwendung und Initialisieren eines Mediensteuerungskanals (sofern zutreffend) durchgeführt. Über den Media Control Channel wird festgelegt, wie das Cast-Framework Nachrichten vom Empfänger des Mediaplayers sendet und empfängt.
Die Streamingsitzung wird automatisch gestartet, wenn der Nutzer ein Gerät aus dem Cast-Symbol auswählt, und wird automatisch beendet, wenn der Nutzer die Verbindung trennt. Eine Verbindung zu einer Empfängersitzung aufgrund von Netzwerkproblemen wird auch automatisch vom Cast-Framework hergestellt.
Streamingsitzungen werden über die GCKSessionManager
verwaltet, auf die über GCKCastContext.sharedInstance().sessionManager
zugegriffen werden kann. Mit den Callbacks „GCKSessionManagerListener
“ können Sie Sitzungsereignisse überwachen, z. B. Erstellung, Sperrung, Wiederaufnahme und Beendigung.
Zuerst müssen wir unseren Sitzungs-Listener registrieren und einige Variablen initialisieren:
class MediaViewController: UIViewController, GCKSessionManagerListener,
GCKRemoteMediaClientListener, LocalPlayerViewDelegate, GCKRequestDelegate {
...
private var sessionManager: GCKSessionManager!
...
required init?(coder: NSCoder) {
super.init(coder: coder)
sessionManager = GCKCastContext.sharedInstance().sessionManager
...
}
override func viewWillAppear(_ animated: Bool) {
...
let hasConnectedSession: Bool = (sessionManager.hasConnectedSession())
if hasConnectedSession, (playbackMode != .remote) {
populateMediaInfo(false, playPosition: 0)
switchToRemotePlayback()
} else if sessionManager.currentSession == nil, (playbackMode != .local) {
switchToLocalPlayback()
}
sessionManager.add(self)
...
}
override func viewWillDisappear(_ animated: Bool) {
...
sessionManager.remove(self)
sessionManager.currentCastSession?.remoteMediaClient?.remove(self)
...
super.viewWillDisappear(animated)
}
func switchToLocalPlayback() {
...
sessionManager.currentCastSession?.remoteMediaClient?.remove(self)
...
}
func switchToRemotePlayback() {
...
sessionManager.currentCastSession?.remoteMediaClient?.add(self)
...
}
// MARK: - GCKSessionManagerListener
func sessionManager(_: GCKSessionManager, didStart session: GCKSession) {
print("MediaViewController: sessionManager didStartSession \(session)")
setQueueButtonVisible(true)
switchToRemotePlayback()
}
func sessionManager(_: GCKSessionManager, didResumeSession session: GCKSession) {
print("MediaViewController: sessionManager didResumeSession \(session)")
setQueueButtonVisible(true)
switchToRemotePlayback()
}
func sessionManager(_: GCKSessionManager, didEnd _: GCKSession, withError error: Error?) {
print("session ended with error: \(String(describing: error))")
let message = "The Casting session has ended.\n\(String(describing: error))"
if let window = appDelegate?.window {
Toast.displayMessage(message, for: 3, in: window)
}
setQueueButtonVisible(false)
switchToLocalPlayback()
}
func sessionManager(_: GCKSessionManager, didFailToStartSessionWithError error: Error?) {
if let error = error {
showAlert(withTitle: "Failed to start a session", message: error.localizedDescription)
}
setQueueButtonVisible(false)
}
func sessionManager(_: GCKSessionManager,
didFailToResumeSession _: GCKSession, withError _: Error?) {
if let window = UIApplication.shared.delegate?.window {
Toast.displayMessage("The Casting session could not be resumed.",
for: 3, in: window)
}
setQueueButtonVisible(false)
switchToLocalPlayback()
}
...
}
Wir würden uns sehr freuen, wenn du in MediaViewController
informiert wirst, wenn wir das Streaming-Gerät verbinden oder trennen. Dann können wir zum lokalen Player wechseln. Beachten Sie, dass die Konnektivität nicht nur durch die Instanz Ihrer App, die auf Ihrem Mobilgerät ausgeführt wird, unterbrochen werden kann, sondern auch durch eine andere Instanz Ihrer (oder einer anderen) Anwendung, die auf einem anderen Mobilgerät ausgeführt wird.
Auf die aktuell aktive Sitzung kann über GCKCastContext.sharedInstance().sessionManager.currentCastSession
zugegriffen werden. Sitzungen werden automatisch erstellt und als Reaktion auf Nutzerbewegungen aus den Streaming-Dialogfeldern gelöscht.
Medien werden geladen
Im Cast SDK umfasst die GCKRemoteMediaClient
eine Reihe praktischer APIs für die Verwaltung der Remote-Medienwiedergabe auf dem Empfänger. Für ein GCKCastSession
, das die Medienwiedergabe unterstützt, wird automatisch eine Instanz von GCKRemoteMediaClient
vom SDK erstellt. Sie können darauf als Eigenschaft remoteMediaClient
der Instanz GCKCastSession
zugreifen.
Fügen Sie zu MediaViewController.swift
den folgenden Code hinzu, um das aktuell ausgewählte Video auf dem Empfänger zu laden:
@objc(MediaViewController)
class MediaViewController: UIViewController, GCKSessionManagerListener,
GCKRemoteMediaClientListener, LocalPlayerViewDelegate, GCKRequestDelegate {
...
@objc func playSelectedItemRemotely() {
loadSelectedItem(byAppending: false)
}
/**
* Loads the currently selected item in the current cast media session.
* @param appending If YES, the item is appended to the current queue if there
* is one. If NO, or if
* there is no queue, a new queue containing only the selected item is created.
*/
func loadSelectedItem(byAppending appending: Bool) {
print("enqueue item \(String(describing: mediaInfo))")
if let remoteMediaClient = sessionManager.currentCastSession?.remoteMediaClient {
let mediaQueueItemBuilder = GCKMediaQueueItemBuilder()
mediaQueueItemBuilder.mediaInformation = mediaInfo
mediaQueueItemBuilder.autoplay = true
mediaQueueItemBuilder.preloadTime = TimeInterval(UserDefaults.standard.integer(forKey: kPrefPreloadTime))
let mediaQueueItem = mediaQueueItemBuilder.build()
if appending {
let request = remoteMediaClient.queueInsert(mediaQueueItem, beforeItemWithID: kGCKMediaQueueInvalidItemID)
request.delegate = self
} else {
let queueDataBuilder = GCKMediaQueueDataBuilder(queueType: .generic)
queueDataBuilder.items = [mediaQueueItem]
queueDataBuilder.repeatMode = remoteMediaClient.mediaStatus?.queueRepeatMode ?? .off
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.mediaInformation = mediaInfo
mediaLoadRequestDataBuilder.queueData = queueDataBuilder.build()
let request = remoteMediaClient.loadMedia(with: mediaLoadRequestDataBuilder.build())
request.delegate = self
}
}
}
...
}
Aktualisieren Sie jetzt verschiedene vorhandene Methoden, um die Cast-Sitzungslogik für die Remote-Wiedergabe zu verwenden:
required init?(coder: NSCoder) {
super.init(coder: coder)
...
castMediaController = GCKUIMediaController()
...
}
func switchToLocalPlayback() {
print("switchToLocalPlayback")
if playbackMode == .local {
return
}
setQueueButtonVisible(false)
var playPosition: TimeInterval = 0
var paused: Bool = false
var ended: Bool = false
if playbackMode == .remote {
playPosition = castMediaController.lastKnownStreamPosition
paused = (castMediaController.lastKnownPlayerState == .paused)
ended = (castMediaController.lastKnownPlayerState == .idle)
print("last player state: \(castMediaController.lastKnownPlayerState), ended: \(ended)")
}
populateMediaInfo((!paused && !ended), playPosition: playPosition)
sessionManager.currentCastSession?.remoteMediaClient?.remove(self)
playbackMode = .local
}
func switchToRemotePlayback() {
print("switchToRemotePlayback; mediaInfo is \(String(describing: mediaInfo))")
if playbackMode == .remote {
return
}
// If we were playing locally, load the local media on the remote player
if playbackMode == .local, (_localPlayerView.playerState != .stopped), (mediaInfo != nil) {
print("loading media: \(String(describing: mediaInfo))")
let paused: Bool = (_localPlayerView.playerState == .paused)
let mediaQueueItemBuilder = GCKMediaQueueItemBuilder()
mediaQueueItemBuilder.mediaInformation = mediaInfo
mediaQueueItemBuilder.autoplay = !paused
mediaQueueItemBuilder.preloadTime = TimeInterval(UserDefaults.standard.integer(forKey: kPrefPreloadTime))
mediaQueueItemBuilder.startTime = _localPlayerView.streamPosition ?? 0
let mediaQueueItem = mediaQueueItemBuilder.build()
let queueDataBuilder = GCKMediaQueueDataBuilder(queueType: .generic)
queueDataBuilder.items = [mediaQueueItem]
queueDataBuilder.repeatMode = .off
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.queueData = queueDataBuilder.build()
let request = sessionManager.currentCastSession?.remoteMediaClient?.loadMedia(with: mediaLoadRequestDataBuilder.build())
request?.delegate = self
}
_localPlayerView.stop()
_localPlayerView.showSplashScreen()
setQueueButtonVisible(true)
sessionManager.currentCastSession?.remoteMediaClient?.add(self)
playbackMode = .remote
}
/* Play has been pressed in the LocalPlayerView. */
func continueAfterPlayButtonClicked() -> Bool {
let hasConnectedCastSession = sessionManager.hasConnectedCastSession
if mediaInfo != nil, hasConnectedCastSession() {
// Display an alert box to allow the user to add to queue or play
// immediately.
if actionSheet == nil {
actionSheet = ActionSheet(title: "Play Item", message: "Select an action", cancelButtonText: "Cancel")
actionSheet?.addAction(withTitle: "Play Now", target: self,
selector: #selector(playSelectedItemRemotely))
}
actionSheet?.present(in: self, sourceView: _localPlayerView)
return false
}
return true
}
Führen Sie die App jetzt auf Ihrem Mobilgerät aus. Stelle eine Verbindung zu deinem Übertragungsgerät her und starte die Wiedergabe eines Videos. Sie sollten das Video sehen, das auf dem Empfänger wiedergegeben wird.
7. Mini-Controller
Gemäß der Checkliste für das Cast-Design müssen alle Cast-Apps einen Mini-Controller bereitstellen, damit sie angezeigt werden, 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 umfasst die Steuerleiste GCKUIMiniMediaControlsViewController
, die den Szenen hinzugefügt werden kann, in denen die persistenten Steuerelemente angezeigt werden sollen.
Für die Beispiel-App verwenden wir den GCKUICastContainerViewController
, der einen weiteren Ansichts-Controller umschließt und unten ein GCKUIMiniMediaControlsViewController
-Element einfügt.
Ändern Sie die Datei AppDelegate.swift
und fügen Sie mit der folgenden Methode den folgenden Code für die Bedingung if useCastContainerViewController
hinzu:
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let appStoryboard = UIStoryboard(name: "Main", bundle: nil)
guard let navigationController = appStoryboard.instantiateViewController(withIdentifier: "MainNavigation")
as? UINavigationController else { return false }
let castContainerVC = GCKCastContext.sharedInstance().createCastContainerController(for: navigationController)
as GCKUICastContainerViewController
castContainerVC.miniMediaControlsItemEnabled = true
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = castContainerVC
window?.makeKeyAndVisible()
...
}
Fügen Sie diese Property und diesen Sender bzw. Getter hinzu, um die Sichtbarkeit des Mini-Controllers zu steuern. Wir verwenden diese in einem späteren Abschnitt:
var isCastControlBarsEnabled: Bool {
get {
if useCastContainerViewController {
let castContainerVC = (window?.rootViewController as? GCKUICastContainerViewController)
return castContainerVC!.miniMediaControlsItemEnabled
} else {
let rootContainerVC = (window?.rootViewController as? RootContainerViewController)
return rootContainerVC!.miniMediaControlsViewEnabled
}
}
set(notificationsEnabled) {
if useCastContainerViewController {
var castContainerVC: GCKUICastContainerViewController?
castContainerVC = (window?.rootViewController as? GCKUICastContainerViewController)
castContainerVC?.miniMediaControlsItemEnabled = notificationsEnabled
} else {
var rootContainerVC: RootContainerViewController?
rootContainerVC = (window?.rootViewController as? RootContainerViewController)
rootContainerVC?.miniMediaControlsViewEnabled = notificationsEnabled
}
}
}
Führen Sie die App aus und streamen Sie ein Video. Wenn die Wiedergabe auf dem Empfänger beginnt, sollte unten in jeder Szene der Mini-Controller angezeigt werden. Mit dem Mini-Controller kannst du die Wiedergabe per Fernzugriff steuern. Wenn Sie zwischen den „Surfen“-Aktivitäten und der lokalen Player-Aktivität wechseln, sollte der Mini-Controller mit dem Medienwiedergabestatus des Empfängers synchron bleiben.
8. Einführendes Overlay
In der Checkliste für das Google Cast-Design muss eine Absender-App Nutzern das Cast-Symbol vorstellen, um sie darüber zu informieren, dass die Absender-App jetzt Cast unterstützt und Nutzern hilft, neu bei Google Cast zu werden.
Die Klasse GCKCastContext
hat die Methode presentCastInstructionsViewControllerOnce
, mit der Sie das Cast-Symbol hervorheben können, wenn es Nutzern zum ersten Mal angezeigt wird. Fügen Sie den folgenden Code in MediaViewController.swift
und MediaTableViewController.swift
ein:
override func viewDidLoad() {
...
NotificationCenter.default.addObserver(self, selector: #selector(castDeviceDidChange),
name: NSNotification.Name.gckCastStateDidChange,
object: GCKCastContext.sharedInstance())
}
@objc func castDeviceDidChange(_: Notification) {
if GCKCastContext.sharedInstance().castState != .noDevicesAvailable {
// You can present the instructions on how to use Google Cast on
// the first time the user uses you app
GCKCastContext.sharedInstance().presentCastInstructionsViewControllerOnce(with: castButton)
}
}
Wenn Sie die App auf Ihrem Mobilgerät ausführen, sollte das Einführungs-Overlay zu sehen sein.
9. Controller maximiert
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.
Der erweiterte Controller ist eine Vollbildansicht, die die vollständige Kontrolle über die Remote-Medienwiedergabe bietet. In dieser Ansicht sollte eine Streaming-App alle verwaltbaren Aspekte einer Streamingsitzung verwalten können – mit Ausnahme der Lautstärkeregelung des Empfängers und des Sitzungslebenszyklus (Verbindung herstellen/beenden). Außerdem finden Sie dort alle Statusinformationen zur Mediasitzung, z. B. Artwork, Titel und Untertitel.
Die Funktion dieser Ansicht wird von der GCKUIExpandedMediaControlsViewController
-Klasse implementiert.
Zuerst müssen Sie den standardmäßigen erweiterten Controller im Umwandlungskontext aktivieren. Ändern Sie AppDelegate.swift
, um den standardmäßigen erweiterten Controller zu aktivieren:
import GoogleCast
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
...
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
// Add after the setShareInstanceWith(options) is set.
GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true
...
}
...
}
Fügen Sie MediaViewController.swift
den folgenden Code hinzu, um den maximierten Controller zu laden, wenn der Nutzer mit dem Streamen eines Videos beginnt:
@objc func playSelectedItemRemotely() {
...
appDelegate?.isCastControlBarsEnabled = false
GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()
}
Der erweiterte Controller wird auch automatisch gestartet, wenn der Nutzer auf den Mini-Controller tippt.
Führen Sie die App aus und streamen Sie ein Video. Sie sollten den maximierten Controller sehen. Kehren Sie zur Liste der Videos zurück. Wenn Sie auf den Mini-Controller klicken, wird der erweiterte Controller wieder geladen.
10. Cast Connect-Support hinzufügen
Über die 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 und die Android TV App fungiert als Empfänger.
Abhängigkeiten
In Podfile
muss der google-cast-sdk
wie unten angegeben auf 4.4.8
oder höher verweisen. Wenn Sie eine Änderung an der Datei vorgenommen haben, führen Sie pod update
über die Console aus, um die Änderung mit Ihrem Projekt zu synchronisieren.
pod 'google-cast-sdk', '>=4.4.8'
GCKLaunch-Optionen
Zum Starten der Android TV App, die auch als Android Receiver bezeichnet wird, muss das Flag androidReceiverCompatible
im Objekt GCKLaunchOptions
auf „true“ gesetzt werden. Dieses GCKLaunchOptions
-Objekt bestimmt, wie der Empfänger gestartet wird und an den GCKCastOptions
übergeben wird, der in der gemeinsam genutzten Instanz mit GCKCastContext.setSharedInstanceWith
festgelegt wird.
Fügen Sie Ihrem AppDelegate.swift
die folgenden Zeilen hinzu:
let options = GCKCastOptions(discoveryCriteria:
GCKDiscoveryCriteria(applicationID: kReceiverAppID))
...
/** Following code enables CastConnect */
let launchOptions = GCKLaunchOptions()
launchOptions.androidReceiverCompatible = true
options.launchOptions = launchOptions
GCKCastContext.setSharedInstanceWith(options)
Anmeldedaten für die Aktivierung festlegen
Auf Absenderseite können Sie mit GCKCredentialsData
angeben, wer an der Sitzung teilnehmen soll. credentials
ist ein String, der vom Nutzer definiert werden kann, solange er von deiner ATV-App erkannt wird. Die GCKCredentialsData
wird nur während der Einführung oder bei der Registrierung an deine Android TV App übergeben. Wenn Sie die Verbindung noch einmal einrichten, während Sie verbunden sind, wird sie nicht an Ihre Android TV App übergeben.
Zum Festlegen von Anmeldedaten für den Start muss GCKCredentialsData
jederzeit nach dem Festlegen von GCKLaunchOptions
definiert werden. Um dies zu demonstrieren, fügen wir der Logik Creds eine Logik hinzu, mit der die Anmeldedaten festgelegt werden, die beim Erstellen der Sitzung übergeben werden. Fügen Sie den folgenden Code in MediaTableViewController.swift
ein:
class MediaTableViewController: UITableViewController, GCKSessionManagerListener, MediaListModelDelegate, GCKRequestDelegate {
...
private var credentials: String? = nil
...
override func viewDidLoad() {
...
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Creds", style: .plain,
target: self, action: #selector(toggleLaunchCreds))
...
setLaunchCreds()
}
...
@objc func toggleLaunchCreds(_: Any){
if (credentials == nil) {
credentials = "{\"userId\":\"id123\"}"
} else {
credentials = nil
}
Toast.displayMessage("Launch Credentials: "+(credentials ?? "Null"), for: 3, in: appDelegate?.window)
print("Credentials set: "+(credentials ?? "Null"))
setLaunchCreds()
}
...
func setLaunchCreds() {
GCKCastContext.sharedInstance()
.setLaunch(GCKCredentialsData(credentials: credentials))
}
}
Anmeldedaten für Ladeanfrage festlegen
Fügen Sie den folgenden Code in die Klasse MediaTableViewController.swift
unter der Funktion loadSelectedItem
ein, um credentials
sowohl in Ihrer Web-App als auch in Ihrer Android TV Receiver App zu verarbeiten:
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
...
mediaLoadRequestDataBuilder.credentials = credentials
...
Je nachdem, an welche Empfänger-App Ihr Absender sendet, werden die oben genannten Anmeldedaten automatisch auf die laufende Sitzung angewendet.
Cast Connect testen
Anleitung zum Installieren des Android TV-APK auf Chromecast mit Google TV
- Suchen Sie die IP-Adresse Ihres Android TV-Geräts. Sie ist normalerweise unter Einstellungen > Netzwerk & Internet > (Netzwerkname, mit dem Ihr Gerät verbunden ist) verfügbar. Auf der rechten Seite werden die Details und die IP-Adresse deines Geräts im Netzwerk angezeigt.
- Verwenden Sie die IP-Adresse Ihres Geräts, um eine Verbindung über ADB mit dem 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/ios_codelab_src
- Installiere die APK-Datei in diesem Ordner mit folgendem Befehl auf deinem Android TV:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Auf dem Android TV-Gerät sollte im Menü Meine Apps jetzt die App YouTube-Videos streamen angezeigt werden.
- Erstellen Sie die App und führen Sie sie auf einem Emulator oder Mobilgerät aus. Wenn Sie eine Streamingsitzung mit Ihrem Android TV-Gerät beginnen, sollte jetzt die Android Receiver App auf Ihrem Android TV-Gerät gestartet werden. Wenn Sie ein Video von Ihrem mobilen iOS-Sender abspielen, sollte es auf dem Android Receiver starten und die Wiedergabe über die Fernbedienung Ihres Android TV-Geräts steuern.
11. Cast-Widgets anpassen
Initialisierung
Beginnen Sie mit dem Ordner „App-Fertig“. Fügen Sie der Methode applicationDidFinishLaunchingWithOptions
in der Datei AppDelegate.swift
Folgendes hinzu:
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let styler = GCKUIStyle.sharedInstance()
...
}
Wenn Sie wie in diesem Codelab beschrieben eine oder mehrere Anpassungen vorgenommen haben, können Sie die Stile übernehmen, indem Sie den Code unten aufrufen.
styler.apply()
Streaming-Ansichten anpassen
Sie können alle Ansichten anpassen, die vom Cast Application Framework verwaltet werden. Dazu lassen sich Standard-Stilrichtlinien für alle Ansichten festlegen. Ändern wir hier als Beispiel die Farbe der Symbolfarbe.
styler.castViews.iconTintColor = .lightGray
Sie können die Standardeinstellungen für einzelne Bildschirme überschreiben. So wird beispielsweise „lightGrayColor“ für die Symbol-Farbfarbe nur für den maximierten Mediacontroller überschrieben.
styler.castViews.mediaControl.expandedController.iconTintColor = .green
Farben ändern
Sie können die Hintergrundfarbe für alle Ansichten oder einzeln für jede Ansicht anpassen. Mit dem folgenden Code wird die Hintergrundfarbe für alle von Cast Application Framework bereitgestellten Ansichten auf Blau festgelegt.
styler.castViews.backgroundColor = .blue
styler.castViews.mediaControl.miniController.backgroundColor = .yellow
Schriftarten ändern
Sie können Schriftarten für verschiedene Labels anpassen, die in Streamingansichten zu sehen sind. Zur Verdeutlichung sollen alle Schriftarten auf „ Kurier Oblique“ gesetzt werden.
styler.castViews.headingTextFont = UIFont.init(name: "Courier-Oblique", size: 16) ?? UIFont.systemFont(ofSize: 16)
styler.castViews.mediaControl.headingTextFont = UIFont.init(name: "Courier-Oblique", size: 6) ?? UIFont.systemFont(ofSize: 6)
Standardbilder von Schaltflächen ändern
Sie können dem Projekt eigene benutzerdefinierte Images hinzufügen und sie den Schaltflächen zuweisen, um sie zu gestalten.
let muteOnImage = UIImage.init(named: "yourImage.png")
if let muteOnImage = muteOnImage {
styler.castViews.muteOnImage = muteOnImage
}
Design des Cast-Symbols ändern
Sie können Streaming-Widgets auch mit dem UIDarstellungsprotokoll gestalten. Der folgende Code steht für GCKUICastButton in allen Ansichten:
GCKUICastButton.appearance().tintColor = UIColor.gray
12. Glückwunsch
Jetzt wissen Sie, wie Sie mit den Cast SDK-Widgets unter iOS eine Video-App aktivieren.
Weitere Informationen finden Sie im Entwicklerleitfaden für iOS.