1. Übersicht
In diesem Codelab erfahren Sie, wie Sie eine vorhandene iOS-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 und Google Cast-fähige Geräte wie einen Fernseher oder ein Soundsystem 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 iOS-Video-App, mit der du Videos auf ein Google Cast-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
- So fügen Sie einen erweiterten Controller hinzu:
- Einführungs-Overlay bereitstellen
- Cast-Widgets anpassen
- Cast Connect einbinden
Voraussetzungen
- Der aktuelle Xcode.
- Ein Mobilgerät mit iOS 9 oder höher (oder der 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 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 Vorkenntnisse in der iOS-Entwicklung.
- Außerdem benötigst du Vorkenntnisse zum Fernsehen.
Wie werden Sie diese Anleitung verwenden?
Wie würden Sie Ihre Erfahrungen im Erstellen von iOS-Apps bewerten?
Wie würdest du deine Erfahrung beim 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 wiedergeben oder auf ein Google Cast-Gerät streamen.
Nachdem Sie den Code heruntergeladen haben, können Sie die fertige Beispielanwendung in Xcode öffnen und ausführen:
Häufig gestellte Fragen
CocoaPods einrichten
Wenn Sie CocoaPods einrichten möchten, rufen Sie die Konsole auf und installieren Sie das Programm mit dem standardmäßig unter macOS verfügbaren Ruby-Code:
sudo gem install cocoapods
Sollten Probleme auftreten, finden Sie weitere Informationen in der offiziellen Dokumentation zum Herunterladen und Installieren des Abhängigkeitsmanagers.
Projekt einrichten
- Rufen Sie Ihr Terminal auf und gehen Sie zum Codelab-Verzeichnis.
- Installieren Sie die Abhängigkeiten aus der Podfile.
cd app-done pod update pod install
- Öffnen Sie Xcode und wählen Sie Open another project... (Weiteres Projekt öffnen...) aus.
- Wählen Sie im Beispielcodeordner 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 unbedingt auf „Zulassen“, wenn die Benachrichtigung zum Annehmen eingehender Netzwerkverbindungen angezeigt wird. Das Cast-Symbol wird nicht angezeigt, wenn diese Option nicht akzeptiert wird.
Klicke auf das Cast-Symbol und wähle dein Google Cast-Gerät aus.
Wähle ein Video aus und klicke auf die Wiedergabeschaltfläche.
Das Video wird auf Ihrem Google Cast-Gerät abgespielt.
Der maximierte Controller wird angezeigt. Mit der Schaltfläche „Wiedergabe/Pause“ kannst du die Wiedergabe steuern.
Zurück zur Videoliste
Unten auf dem Bildschirm ist jetzt ein Mini-Controller zu sehen.
Klicke auf die Pause-Taste im Mini-Controller, um das Video auf dem Receiver zu pausieren. Klicke auf die Wiedergabeschaltfläche im Minicontroller, um die Wiedergabe des Videos fortzusetzen.
Klicke auf das Cast-Symbol, um das Streamen auf das Google Cast-Gerät zu beenden.
4. Startprojekt vorbereiten
Wir müssen die heruntergeladene Start-App für Google Cast unterstützen. Hier sind einige Google Cast-Begriffe, die wir in diesem Codelab verwenden werden:
- Eine Absender-App wird auf einem Mobilgerät oder Laptop ausgeführt.
- Eine Empfänger-App wird auf dem Google Cast-Gerät ausgeführt.
Projekt einrichten
Jetzt können Sie auf dem Startprojekt mit Xcode aufbauen:
- Rufen Sie Ihr Terminal auf und gehen Sie zum Codelab-Verzeichnis.
- Installieren Sie die Abhängigkeiten aus der Podfile.
cd app-start pod update pod install
- Öffnen Sie Xcode und wählen Sie Open another project... (Weiteres Projekt öffnen...) aus.
- Wählen Sie im Beispielcodeordner die Datei
CastVideos-ios.xcworkspace
aus dem Verzeichnisapp-start
aus.
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 Hauptansicht-Controllern: MediaTableViewController
und MediaViewController.
.
MediaTableViewController
Dieser UITableViewController zeigt eine Liste der Videos einer MediaListModel
-Instanz an. Die Liste der Videos und die zugehörigen Metadaten werden als JSON-Datei auf einem Remoteserver gehostet. MediaListModel
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 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 laden zu können.
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 es dem Nutzer, das Video lokal auf dem Mobilgerät abzuspielen.
Der Ansicht-Controller hostet LocalPlayerView
, einige Mediensteuerelemente und einen Textbereich für die Beschreibung des ausgewählten Videos. Der Player deckt den oberen Teil des Bildschirms ab. So bleibt Platz für eine detaillierte Beschreibung des Videos unterhalb des Nutzers, wo die Wiedergabe/Pause oder die lokale Wiedergabe des Videos gestartet werden kann.
Häufig gestellte Fragen
5. Cast-Symbol hinzufügen
Eine Cast-fähige Anwendung zeigt das Cast-Symbol in jedem Ansichtscontroller 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 auf einem beliebigen Bildschirm Ihrer App mit dem Übertragungsgerät zu verbinden oder die Verbindung damit zu trennen, wie in der Google Cast-Design-Checkliste beschrieben.
Konfiguration
Für das Startprojekt müssen dieselben Abhängigkeiten und Xcode-Einrichtung wie für die fertige 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 ein globales Singleton-Objekt, das GCKCastContext
, das alle Aktivitäten des Frameworks koordiniert. Dieses Objekt muss früh im Lebenszyklus der Anwendung initialisiert werden, in der Regel in der Methode application(_:didFinishLaunchingWithOptions:)
des App-Delegaten, damit die automatische Sitzungswiederaufnahme beim Neustart der Absenderanwendung ordnungsgemäß ausgelöst werden kann und das Scannen für Geräte beginnen 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. Die wichtigste davon ist die Empfänger-App-ID, mit der Ergebnisse der Cast-Geräteerkennung gefiltert und die Empfängeranwendung gestartet wird, wenn eine Cast-Sitzung gestartet wird.
Die Methode application(_:didFinishLaunchingWithOptions:)
ist auch ein guter Ort, um einen Logging-Bevollmächtigten einzurichten, der die Logging-Nachrichten aus dem Cast-Framework empfängt. Diese können für die Fehlerbehebung und Fehlerbehebung nützlich sein.
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 AppDelegate.swift
den folgenden Code hinzu, um GCKCastContext
mit der Anwendungs-ID aus den Nutzer-Standardeinstellungen zu initialisieren, und 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 bietet eine Cast-Schaltflächenkomponente namens GCKUICastButton
als abgeleitete Klasse von UIButton
. Sie kann der Titelleiste der App hinzugefügt werden, indem Sie sie in ein UIBarButtonItem
einschließen. Wir müssen das Cast-Symbol sowohl MediaTableViewController
als auch MediaViewController
hinzufügen.
Fügen Sie MediaTableViewController.swift
und MediaViewController.swift
den folgenden Code hinzu:
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 zu MediaViewController.swift
hinzu:
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 jetzt die App aus. In der Navigationsleiste der App sollte ein Cast-Symbol angezeigt werden. Wenn Sie darauf klicken, werden die Cast-Geräte in Ihrem lokalen Netzwerk aufgelistet. Die Geräteerkennung wird automatisch von GCKCastContext
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. Klicke auf das Cast-Symbol, um das Streamen zu beenden.
6. Videoinhalte streamen
Die Beispiel-App wird erweitert, damit du Videos auch per Fernzugriff auf einem Übertragungsgerät wiedergeben kannst. Dazu müssen wir die verschiedenen Ereignisse beobachten, die vom Cast-Framework generiert werden.
Medien streamen
Wenn Sie Medien auf einem Übertragungsgerät abspielen möchten, müssen folgende Voraussetzungen erfüllt sein:
- Erstellen Sie ein
GCKMediaInformation
-Objekt aus dem Cast SDK, mit dem ein Medienelement modelliert wird. - 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. - Medienstatus verfolgen
- Sende Wiedergabebefehle basierend auf Nutzerinteraktionen 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 die Kapselung unserer App für ein Mediakostenelement. Wir können MediaItem
einfach einem GCKMediaInformation
zuordnen. Wir haben Schritt 2 bereits im vorherigen Abschnitt ausgeführt. Schritt 3 ist mit dem Cast SDK ganz einfach.
Die Beispiel-App MediaViewController
unterscheidet mithilfe der folgenden Aufzählung bereits zwischen der lokalen und der Remote-Wiedergabe:
enum PlaybackMode: Int {
case none = 0
case local
case remote
}
private var playbackMode = PlaybackMode.none
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 Ansicht-Controller das Streamen 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-Framework übernommen.
Streamingsitzungen werden von der GCKSessionManager
verwaltet, auf die über GCKCastContext.sharedInstance().sessionManager
zugegriffen werden kann. Mit den GCKSessionManagerListener
-Callbacks können Sitzungsereignisse wie Erstellen, Sperren, Wiederaufnahme und Beenden überwacht werden.
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()
}
...
}
In der MediaViewController
geben wir an, dass wir Sie informieren möchten, wenn die Verbindung zum Cast-Gerät 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 GCKCastContext.sharedInstance().sessionManager.currentCastSession
zugegriffen werden. Sitzungen werden automatisch erstellt und gelöscht, wenn Nutzerbewegungen aus den Übertragungsdialogen ausgeführt werden.
Medien werden geladen
Im Cast SDK bietet der GCKRemoteMediaClient
eine Reihe praktischer APIs zur Verwaltung der Remote-Medienwiedergabe auf dem Empfänger. Bei einem GCKCastSession
, der die Medienwiedergabe unterstützt, wird vom SDK automatisch eine Instanz von GCKRemoteMediaClient
erstellt. Sie kann über die Eigenschaft remoteMediaClient
der Instanz GCKCastSession
aufgerufen werden.
Fügen Sie 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 nun 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. 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 bereitstellen, der angezeigt wird, wenn der Nutzer die aktuelle Seite 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 eingeblendet werden sollen.
In der Beispielanwendung verwenden wir den GCKUICastContainerViewController
, der einen weiteren Ansicht-Controller umschließt und unten ein GCKUIMiniMediaControlsViewController
hinzufügt.
Ändern Sie die Datei AppDelegate.swift
und fügen Sie 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 Eigenschaft und den Setter/Getter hinzu, um die Sichtbarkeit des Minicontrollers zu steuern. Diese werden wir in einem späteren Abschnitt verwenden.
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
}
}
}
App ausführen und Video streamen Wenn die Wiedergabe auf dem Receiver beginnt, sollte unten in jeder Szene 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. Einführungs-Overlay
In der Checkliste für das Design von Google Cast muss eine Absender-App das Cast-Symbol bestehenden Nutzern einführen, um ihnen mitzuteilen, dass die Absender-App jetzt Streaming unterstützt und auch Nutzern hilft, die neu auf Google Cast sind.
Die Klasse GCKCastContext
hat die Methode presentCastInstructionsViewControllerOnce
, mit der das Cast-Symbol hervorgehoben werden kann, wenn es dem Nutzer erstmals angezeigt wird. Fügen Sie MediaViewController.swift
und MediaTableViewController.swift
den folgenden Code hinzu:
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, sollten Sie das Einführungs-Overlay sehen.
9. 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.
Der maximierte Controller ist eine Vollbildansicht, über die Sie die Remote-Medienwiedergabe vollständig steuern können. In dieser Ansicht sollte eine Streaming-App alle verwaltbaren Aspekte einer Streamingsitzung verwalten können – mit Ausnahme der Lautstärkeregelung für Empfänger und des Sitzungslebenszyklus (Verbindung herstellen/stoppen). Außerdem finden Sie hier alle Statusinformationen zur Mediensitzung (z. B. Artwork, Titel und Untertitel).
Die Funktion dieser Ansicht wird von der Klasse GCKUIExpandedMediaControlsViewController
implementiert.
Als Erstes müssen Sie den standardmäßigen erweiterten Controller im Cast-Kontext 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, damit der maximierte Controller geladen wird, wenn der Nutzer mit dem Streamen eines Videos beginnt:
@objc func playSelectedItemRemotely() {
...
appDelegate?.isCastControlBarsEnabled = false
GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()
}
Der maximierte Controller wird automatisch gestartet, wenn der Nutzer auf den Minicontroller tippt.
App ausführen und Video 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.
10. 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
Achten Sie bei Podfile
darauf, dass google-cast-sdk
auf 4.4.8
oder einen höheren Wert ausgerichtet ist (siehe unten). 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 App für Android TV, auch Android Receiver genannt, müssen Sie das androidReceiverCompatible
-Objekt im Objekt GCKLaunchOptions
auf „true“ setzen. Dieses GCKLaunchOptions
-Objekt gibt vor, wie der Empfänger gestartet wird, und wird an GCKCastOptions
übergeben, die in der freigegebenen Instanz mit GCKCastContext.setSharedInstanceWith
festgelegt werden.
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 Einführung festlegen
Auf der Seite des Absenders können Sie angeben, wer GCKCredentialsData
der Sitzung beitreten darf. credentials
ist ein String, der vom Nutzer definiert werden kann, solange Ihre ATV-App ihn verstehen kann. Die GCKCredentialsData
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 GCKCredentialsData
nach dem Festlegen von GCKLaunchOptions
jederzeit definiert werden. Um dies zu veranschaulichen, fügen wir eine Logik für die Schaltfläche Krednen hinzu, um Anmeldedaten festzulegen, die beim Erstellen der Sitzung übergeben werden sollen. Fügen Sie den folgenden Code zu Ihrem MediaTableViewController.swift
hinzu:
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 Anfrage zum Laden festlegen
Um credentials
sowohl in Ihrer Web-App als auch in Ihrer Android TV Receiver App zu verarbeiten, fügen Sie den folgenden Code in Ihre MediaTableViewController.swift
-Klasse unter der Funktion loadSelectedItem
ein:
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
...
mediaLoadRequestDataBuilder.credentials = credentials
...
Je nach Empfänger-App, an die der Absender streamt, wendet das SDK die oben genannten Anmeldedaten automatisch auf die laufende Sitzung an.
Cast Connect testen
Android TV-APK auf Chromecast mit Google TV installieren
- Suchen Sie die IP-Adresse Ihres Android TV-Geräts. Sie finden diese Option in der Regel unter Einstellungen > Netzwerk & Internet > (Netzwerkname, mit dem Ihr Gerät verbunden ist). Rechts werden die Details und die IP-Adresse Ihres Geräts im Netzwerk angezeigt.
- Verwenden Sie die IP-Adresse für Ihr Gerät, um über ADB eine Verbindung über das Terminal herzustellen:
$ adb connect <device_ip_address>:5555
- Gehen Sie im Terminalfenster zum Ordner der obersten Ebene für die Codelab-Beispiele, die Sie zu Beginn dieses Codelabs heruntergeladen haben. Beispiel:
$ cd Desktop/ios_codelab_src
- Installieren Sie die APK-Datei in diesem Ordner auf Ihrem Android TV:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Auf Ihrem Android TV-Gerät sollte jetzt im Menü Meine Apps eine App mit dem Namen Videos streamen zu sehen sein.
- Anschließend können Sie die App auf einem Emulator oder Mobilgerät erstellen und ausführen. Nach dem Einrichten einer Streamingsitzung mit Ihrem Android TV-Gerät sollte die Android Receiver App auf Ihrem Android TV-Gerät gestartet werden. Wenn Sie ein Video von Ihrem iOS-Absender auf dem Gerät wiedergeben, sollte es im Android Receiver gestartet und die Wiedergabe mit der Fernbedienung Ihres Android TV-Geräts gesteuert werden.
11. Cast-Widgets anpassen
Initialisierung
Beginnen Sie mit dem Ordner „App-Fertig“. Fügen Sie der Datei applicationDidFinishLaunchingWithOptions
in der Datei AppDelegate.swift
Folgendes hinzu:
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let styler = GCKUIStyle.sharedInstance()
...
}
Wenn Sie eine oder mehrere Anpassungen wie im Rest dieses Codelabs beschrieben abgeschlossen haben, können Sie die Stile mithilfe des folgenden Codes aufrufen.
styler.apply()
Cast-Ansichten anpassen
Sie können alle Ansichten anpassen, die vom Cast Application Framework verwaltet werden, indem Sie für alle Ansichten Standardstilrichtlinien festlegen. Nehmen wir als Beispiel die Farbe der Symbolfärbung.
styler.castViews.iconTintColor = .lightGray
Sie können die Standardwerte bei Bedarf für einzelne Bildschirme überschreiben. So wird beispielsweise „lightGrayColor“ für die Farbe der Symbolfarbe 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 für jede Ansicht individuell 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 zu Illustrationszwecken auf „Courier-Oblique“ festgelegt 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)
Bilder der Standardschaltfläche ändern
Sie können dem Projekt eigene benutzerdefinierte Images hinzufügen und die Images Ihren Schaltflächen zuweisen, um sie zu gestalten.
let muteOnImage = UIImage.init(named: "yourImage.png")
if let muteOnImage = muteOnImage {
styler.castViews.muteOnImage = muteOnImage
}
Cast-Symboldesign ändern
Sie können Cast-Widgets auch mithilfe des UIDarstellungsprotokolls gestalten. Der folgende Code spiegelt das GCKUICastButton-Symbol in allen angezeigten Ansichten wider:
GCKUICastButton.appearance().tintColor = UIColor.gray
12. Glückwunsch
Jetzt wissen Sie, wie Sie mit den Cast SDK-Widgets unter iOS eine Video-App für Google Cast aktivieren.
Weitere Informationen finden Sie im Entwicklerleitfaden iOS Sender.