In diesem Entwicklerleitfaden wird beschrieben, wie Sie die Google Cast-Unterstützung auf Ihrem iOS-Gerät einrichten. die das iOS Sender SDK verwendet.
Das Mobilgerät oder der Laptop ist der Sender, der die Wiedergabe steuert. Das Google Cast-Gerät ist der Empfänger, mit dem die Inhalte auf dem Fernseher wiedergegeben werden.
Das Absender-Framework bezieht sich auf das Binärprogramm der Cast-Klassenbibliothek und die zugehörigen Ressourcen, die zur Laufzeit auf dem Absender vorhanden sind. Die Absender-App oder die Cast App bezieht sich auf eine App, die auch auf dem Absender ausgeführt wird. Web Receiver App bezieht sich auf die HTML-Anwendung, die auf Web Receiver ausgeführt wird.
Das Absender-Framework nutzt ein asynchrones Callback-Design, um den Absender zu informieren. App für Ereignisse und den Wechsel zwischen verschiedenen Stadien der Cast App. Zyklus.
Anwendungsfluss
In den folgenden Schritten wird der typische allgemeine Ausführungsablauf für einen Absender beschrieben iOS-App:
- Das Cast-Framework beginnt,
GCKDiscoveryManager
basierend auf den Eigenschaften inGCKCastOptions
bis mit der Suche nach Geräten beginnen. - Wenn der Nutzer auf das Cast-Symbol klickt, zeigt das Framework das Cast-Symbol mit der Liste der gefundenen Übertragungsgeräte.
- Wenn der Nutzer ein Übertragungsgerät auswählt, versucht das Framework, die Web Receiver auf dem Übertragungsgerät.
- Das Framework ruft Callbacks in der Absender-App auf, um zu bestätigen, dass der Web Receiver-App wurde gestartet.
- Das Framework schafft einen Kommunikationskanal zwischen Sender und Web Receiver-Apps.
- Das Framework nutzt den Kommunikationskanal, um Medien zu laden und zu steuern auf dem Web Receiver wiedergegeben werden.
- Das Framework synchronisiert den Status der Medienwiedergabe zwischen Absender und Web Receiver: Wenn der Nutzer UI-Aktionen für Absender durchführt, wird das Framework übergeben. Mediensteuerungsanfragen an den Web Receiver gesendet werden, Medienstatusaktualisierungen sendet, aktualisiert das Framework den Status der Absender-UI.
- Wenn der Nutzer auf das Cast-Symbol klickt, um die Verbindung zum Übertragungsgerät zu trennen, trennt das Framework die Absender-App vom Web Receiver.
Um Fehler beim Absender zu beheben, müssen Sie die Protokollierung aktivieren.
Für eine umfassende Liste aller Klassen, Methoden und Ereignisse in Google Cast iOS-Framework, siehe Google Cast iOS API Referenz. In den folgenden Abschnitten werden die einzelnen Schritte zur Integration von Cast in Ihre iOS-App.
Aufrufmethoden aus dem Hauptthread
Cast-Kontext initialisieren
Das Cast-Framework hat ein globales Singleton-Objekt, das
GCKCastContext
, die
koordiniert alle Aktivitäten des Frameworks. Dieses Objekt muss initialisiert werden
im Lebenszyklus der Anwendung, in der Regel
-[application:didFinishLaunchingWithOptions:]
des App-Delegaten, sodass
dass die automatische
Wiederaufnahme der Sitzung beim Neustart der
App des Absenders korrekt ausgelöst werden kann.
GCKCastOptions
-Objekt muss beim Initialisieren von GCKCastContext
angegeben werden.
Diese Klasse enthält Optionen, die das Verhalten des Frameworks beeinflussen. Die meisten
wichtig ist die Web Receiver-Anwendungs-ID, die zum Filtern
und die Web Receiver App zu starten, wenn ein Stream läuft
begonnen.
Auch die Methode -[application:didFinishLaunchingWithOptions:]
eignet sich gut.
um einen Logging-Delegaten einzurichten, der die Logging-Nachrichten vom Framework empfangen soll.
Diese können bei der Fehlersuche und Fehlerbehebung hilfreich sein.
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, GCKLoggerDelegate { let kReceiverAppID = kGCKDefaultMediaReceiverApplicationID let kDebugLoggingEnabled = true var window: UIWindow? func applicationDidFinishLaunching(_ application: UIApplication) { let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID) let options = GCKCastOptions(discoveryCriteria: criteria) GCKCastContext.setSharedInstanceWith(options) // Enable logger. GCKLogger.sharedInstance().delegate = self ... } // MARK: - GCKLoggerDelegate func logMessage(_ message: String, at level: GCKLoggerLevel, fromFunction function: String, location: String) { if (kDebugLoggingEnabled) { print(function + " - " + message) } } }
AppDelegate.h
@interface AppDelegate () <GCKLoggerDelegate> @end
AppDelegate.m
@implementation AppDelegate static NSString *const kReceiverAppID = @"AABBCCDD"; static const BOOL kDebugLoggingEnabled = YES; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { GCKDiscoveryCriteria *criteria = [[GCKDiscoveryCriteria alloc] initWithApplicationID:kReceiverAppID]; GCKCastOptions *options = [[GCKCastOptions alloc] initWithDiscoveryCriteria:criteria]; [GCKCastContext setSharedInstanceWithOptions:options]; // Enable logger. [GCKLogger sharedInstance].delegate = self; ... return YES; } ... #pragma mark - GCKLoggerDelegate - (void)logMessage:(NSString *)message atLevel:(GCKLoggerLevel)level fromFunction:(NSString *)function location:(NSString *)location { if (kDebugLoggingEnabled) { NSLog(@"%@ - %@, %@", function, message, location); } } @end
Die Cast UX-Widgets
Das Cast iOS SDK stellt diese Widgets bereit, die dem Cast-Design entsprechen. Checkliste:
Einführendes Overlay: Die Klasse
GCKCastContext
hat eine Methode,presentCastInstructionsViewControllerOnceWithCastButton
Damit wird das Cast-Symbol beim ersten Webempfänger hervorgehoben. verfügbar ist. Die Absender-App kann den Text und die Position des Titels anpassen und die Schaltfläche „Schließen“.Cast-Symbol: Ab Version 4.6.0 des Cast iOS Sender SDK ist das Cast-Symbol immer sichtbar wenn das Absendergerät mit dem WLAN verbunden ist. Wenn die Nutzenden zum ersten Mal Nach dem ersten Start der App erscheint auf dem Cast-Symbol ein Berechtigungsdialogfeld. damit der Nutzer der App lokalen Netzwerkzugriff auf Geräte auf Netzwerk. Wenn der Nutzer anschließend auf das Cast-Symbol tippt, wird eine Übertragung wird angezeigt, in dem die erkannten Geräte aufgeführt sind. Wenn Nutzende auf über das Cast-Symbol, während das Gerät verbunden ist, wird die aktuelle Medienmetadaten (z. B. Titel, Name des Tonstudios und ein Thumbnail) Bild) oder ermöglicht dem Nutzer, die Verbindung zum Übertragungsgerät zu trennen. Wenn Nutzende auf das Cast-Symbol tippt, während keine Geräte verfügbar sind, oder ein Bildschirm wird angezeigt und der Nutzer wird darüber informiert, warum Geräte nicht gefunden wurden. und zur Fehlerbehebung.
Mini-Controller: Wenn der Nutzer Inhalte streamt und die aktuelle Seite verlassen hat Inhaltsseite oder maximierter Controller auf einen anderen Bildschirm in der Sender-App, wird unten auf dem Bildschirm angezeigt, die gerade gestreamten Medienmetadaten abrufen und die Wiedergabe steuern können.
Erweiterter Controller: Wenn der Nutzer Inhalte streamt, klickt er auf die Medienbenachrichtigung oder wird der erweiterte Controller gestartet, der die die gerade Medienmetadaten wiedergeben, und bietet mehrere Schaltflächen zum Steuern der Medienwiedergabe.
Cast-Symbol hinzufügen
Das Framework stellt eine Komponente für das Cast-Symbol als abgeleitete UIButton
-Klasse bereit. Es kann
kann der Titelleiste der App hinzugefügt werden, indem er sie in ein UIBarButtonItem
setzt. Ein typisches
So kann die abgeleitete UIViewController
-Klasse ein Cast-Symbol installieren:
let castButton = GCKUICastButton(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) castButton.tintColor = UIColor.gray navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
GCKUICastButton *castButton = [[GCKUICastButton alloc] initWithFrame:CGRectMake(0, 0, 24, 24)]; castButton.tintColor = [UIColor grayColor]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:castButton];
Wenn Sie auf die Schaltfläche tippen, wird standardmäßig das Cast-Dialogfeld geöffnet, das vom Framework.
GCKUICastButton
können auch direkt zum Storyboard hinzugefügt werden.
Geräteerkennung konfigurieren
Im Framework erfolgt die Geräteerkennung automatisch. Es ist nicht nötig, den Erkennungsprozess explizit starten oder anhalten, es sei denn, Sie implementieren eine benutzerdefinierte UI.
Die Erkennung im Framework wird von der Klasse verwaltet
GCKDiscoveryManager
,
das eine Eigenschaft des
GCKCastContext
Die
bietet eine standardmäßige Cast-Dialogkomponente für die Geräteauswahl und
Steuerung. Die Geräteliste ist lexikografisch nach dem für das Gerät angezeigten Namen geordnet.
Funktionsweise der Sitzungsverwaltung
Mit dem Cast SDK wird das Konzept einer Cast-Sitzung eingeführt. Einrichtung, die die Schritte zum Herstellen einer Verbindung mit einem Gerät, dem Starten (oder dem Beitritt) zu einem Web umfasst Receiver-App, die eine Verbindung zu dieser App herstellt und ein Mediensteuerungskanal initialisiert wird. Web Receiver anzeigen Leitfaden zum Lebenszyklus von Anwendungen finden Sie weitere Informationen zu Übertragungssitzungen und zum Lebenszyklus des Web-Receivers.
Sitzungen werden vom Kurs verwaltet
GCKSessionManager
,
das eine Eigenschaft des
GCKCastContext
Einzelne Sitzungen werden durch Unterklassen der Klasse dargestellt.
GCKSession
: z. B.
GCKCastSession
Sitzungen mit Übertragungsgeräten. Du kannst auf das derzeit aktive Streaming zugreifen
Sitzung (falls vorhanden) als currentCastSession
-Property von GCKSessionManager
.
Die
GCKSessionManagerListener
können Sie Sitzungsereignisse überwachen, z. B. Sitzungserstellung,
Sperrung, Wiederaufnahme und Kündigung. Das Framework sperrt automatisch
Sitzungen, bei denen die Sender-App in den Hintergrund wechselt und versucht, sie fortzusetzen
wenn die App in den Vordergrund zurückkehrt (oder erneut gestartet wird, nachdem
abnormale/abrupte Beendigung einer App während einer aktiven Sitzung).
Wenn das Dialogfeld „Streamen“ verwendet wird, werden Sitzungen erstellt und gelöscht.
automatisch auf Gesten reagieren. Andernfalls kann die App
Sitzungen explizit über Methoden auf
GCKSessionManager
Ob die Anwendung als Reaktion auf den Sitzungslebenszyklus eine spezielle Verarbeitung durchführen muss
kann es eine oder mehrere GCKSessionManagerListener
-Instanzen mit
GCKSessionManager
. GCKSessionManagerListener
ist ein Protokoll, mit dem
Callbacks für Ereignisse wie Sitzungsbeginn und ‐ende an.
Stream-Übertragung
Die Beibehaltung des Sitzungsstatus ist die Grundlage der Streamübertragung. können Nutzer vorhandene Audio- und Videostreams per Sprachbefehl, über Google Home eine App oder ein Smart Display verwenden. Die Medienwiedergabe wird auf einem Gerät (Quelle) gestoppt und auf einem anderen fortgesetzt (das Ziel). Jedes Übertragungsgerät mit der neuesten Firmware kann als Quelle oder Ziel in einem Streamübertragung.
Um während der Stream-Übertragung das neue Zielgerät abzurufen, verwende die
GCKCastSession#device
Property während des
[sessionManager:didResumeCastSession:]
Callback des Nutzers an.
Weitere Informationen finden Sie unter Stream-Übertragung mit Web Receiver .
Automatische Wiederherstellung der Verbindung
Das Cast-Framework fügt Logik zum erneuten Verbindungsaufbau hinzu, um die erneute Verbindung automatisch zu verarbeiten. in vielen subtilen Sonderfällen, wie z. B.:
- Wiederherstellung nach einem vorübergehenden WLAN-Ausfall
- Aus Geräte-Ruhemodus wiederherstellen
- Nach Hintergrundwiedergabe wiederherstellen
- Wiederherstellung nach einem Absturz der App
So funktioniert die Mediensteuerung
Wenn das Streamen mit einer Web Receiver-App eingerichtet wird, die diese Medien unterstützt
Namespace, eine Instanz von
GCKRemoteMediaClient
werden automatisch vom Framework erstellt. ist der Zugriff als
remoteMediaClient
-Eigenschaft des
GCKCastSession
Instanz.
Alle Methoden unter GCKRemoteMediaClient
, die Anfragen an den Web Receiver senden
wird ein
Objekt GCKRequest
, das
kann verwendet werden,
um diese Anfrage zu verfolgen. A
GCKRequestDelegate
kann diesem Objekt zugewiesen werden, um Benachrichtigungen
Ergebnis des Vorgangs.
Es wird erwartet, dass die Instanz von GCKRemoteMediaClient
kann von mehreren Teilen der App und einigen internen Komponenten gemeinsam genutzt werden.
des Frameworks wie dem Cast-Dialogfeld und der Mini-Mediensteuerung teilen sich
Instanz. Aus diesem Grund GCKRemoteMediaClient
unterstützt die Registrierung mehrerer
GCKRemoteMediaClientListener
.
Medienmetadaten festlegen
Die
GCKMediaMetadata
stellt Informationen zu einem Medienelement dar, das Sie streamen möchten. Die folgenden
erstellt eine neue GCKMediaMetadata
-Instanz eines Films und legt den Titel fest,
Untertitel, den Namen des Aufnahmestudios und zwei Bilder.
let metadata = GCKMediaMetadata() metadata.setString("Big Buck Bunny (2008)", forKey: kGCKMetadataKeyTitle) metadata.setString("Big Buck Bunny tells the story of a giant rabbit with a heart bigger than " + "himself. When one sunny day three rodents rudely harass him, something " + "snaps... and the rabbit ain't no bunny anymore! In the typical cartoon " + "tradition he prepares the nasty rodents a comical revenge.", forKey: kGCKMetadataKeySubtitle) metadata.addImage(GCKImage(url: URL(string: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg")!, width: 480, height: 360))
GCKMediaMetadata *metadata = [[GCKMediaMetadata alloc] initWithMetadataType:GCKMediaMetadataTypeMovie]; [metadata setString:@"Big Buck Bunny (2008)" forKey:kGCKMetadataKeyTitle]; [metadata setString:@"Big Buck Bunny tells the story of a giant rabbit with a heart bigger than " "himself. When one sunny day three rodents rudely harass him, something " "snaps... and the rabbit ain't no bunny anymore! In the typical cartoon " "tradition he prepares the nasty rodents a comical revenge." forKey:kGCKMetadataKeySubtitle]; [metadata addImage:[[GCKImage alloc] initWithURL:[[NSURL alloc] initWithString:@"https://commondatastorage.googleapis.com/" "gtv-videos-bucket/sample/images/BigBuckBunny.jpg"] width:480 height:360]];
Weitere Informationen finden Sie im Abschnitt zur Bildauswahl und Caching zur Verwendung von Bildern mit Medienmetadaten.
Medien laden
Um ein Medienelement zu laden, erstellen Sie ein
GCKMediaInformation
-Instanz mithilfe der Metadaten der Medien. Rufen Sie dann den aktuellen
GCKCastSession
und
verwenden Sie
GCKRemoteMediaClient
um die Medien in die Empfänger-App zu laden. Sie können dann GCKRemoteMediaClient
verwenden.
zur Steuerung einer auf dem Empfänger
ausgeführten Mediaplayer-App,
anhalten und stoppen.
let url = URL.init(string: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4") guard let mediaURL = url else { print("invalid mediaURL") return } let mediaInfoBuilder = GCKMediaInformationBuilder.init(contentURL: mediaURL) mediaInfoBuilder.streamType = GCKMediaStreamType.none; mediaInfoBuilder.contentType = "video/mp4" mediaInfoBuilder.metadata = metadata; mediaInformation = mediaInfoBuilder.build() guard let mediaInfo = mediaInformation else { print("invalid mediaInformation") return } if let request = sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInfo) { request.delegate = self }
GCKMediaInformationBuilder *mediaInfoBuilder = [[GCKMediaInformationBuilder alloc] initWithContentURL: [NSURL URLWithString:@"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"]]; mediaInfoBuilder.streamType = GCKMediaStreamTypeNone; mediaInfoBuilder.contentType = @"video/mp4"; mediaInfoBuilder.metadata = metadata; self.mediaInformation = [mediaInfoBuilder build]; GCKRequest *request = [self.sessionManager.currentSession.remoteMediaClient loadMedia:self.mediaInformation]; if (request != nil) { request.delegate = self; }
Weitere Informationen finden Sie im Abschnitt mit Media-Tracks.
4K-Videoformat
Um das Videoformat deiner Medien zu bestimmen, verwende das Attribut videoInfo
von
GCKMediaStatus
um die aktuelle Instanz von
GCKVideoInfo
Diese Instanz enthält den Typ des HDR TV-Formats sowie die Höhe und Breite in
Pixel. Varianten des 4K-Formats sind im Attribut hdrType
durch enum angegeben
Werte GCKVideoInfoHDRType
.
Mini-Controller hinzufügen
Gemäß dem Cast-Design Checkliste, sollte eine Absender-App eine dauerhafte Steuerung bieten, die sogenannte Miniversion. Controller die angezeigt werden sollte, wenn der Nutzer die aktuelle Inhaltsseite verlässt. Der Mini-Controller ermöglicht sofortigen Zugriff und eine sichtbare Erinnerung für den aktuelle Streamsitzung.
Das Cast-Framework bietet eine Steuerleiste,
GCKUIMiniMediaControlsViewController
,
das zu den Szenen hinzugefügt werden kann, in denen du den Mini-Controller zeigen möchtest.
Wenn die Sender-App einen Video- oder Audio-Livestream wiedergibt, gibt das SDK zeigt automatisch eine Wiedergabe-/Stopp-Schaltfläche anstelle der Wiedergabe-/Pause-Schaltfläche an. im Mini-Controller.
Unter iOS-Sender-UI anpassen finden Sie Informationen zur Absender-App die Darstellung der Cast-Widgets konfigurieren kann.
Es gibt zwei Möglichkeiten, den Mini-Controller einer Sender-App hinzuzufügen:
- Das Layout des Mini-Controllers lässt sich mit dem Cast Framework verwalten, mit einem eigenen Ansichts-Controller.
- Sie können das Layout des Mini-Controller-Widgets selbst verwalten, indem Sie es Ihrer vorhandenen View-Controller erstellen, indem Sie im Storyboard eine Unteransicht bereitstellen.
Wrapping mit GCKUICastContainerViewController
Die erste Möglichkeit besteht darin,
GCKUICastContainerViewController
das einen weiteren Ansichts-Controller umschließt und ein
GCKUIMiniMediaControlsViewController
. Dieser Ansatz ist insofern eingeschränkt, als Sie das Attribut
Animation und kann das Verhalten des Containeransicht-Controllers nicht konfigurieren.
Diese erste Methode wird in der Regel
-[application:didFinishLaunchingWithOptions:]
-Methode des Anwendungsdelegats:
func applicationDidFinishLaunching(_ application: UIApplication) { ... // Wrap main view in the GCKUICastContainerViewController and display the mini controller. let appStoryboard = UIStoryboard(name: "Main", bundle: nil) let navigationController = appStoryboard.instantiateViewController(withIdentifier: "MainNavigation") let castContainerVC = GCKCastContext.sharedInstance().createCastContainerController(for: navigationController) castContainerVC.miniMediaControlsItemEnabled = true window = UIWindow(frame: UIScreen.main.bounds) window!.rootViewController = castContainerVC window!.makeKeyAndVisible() ... }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... // Wrap main view in the GCKUICastContainerViewController and display the mini controller. UIStoryboard *appStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UINavigationController *navigationController = [appStoryboard instantiateViewControllerWithIdentifier:@"MainNavigation"]; GCKUICastContainerViewController *castContainerVC = [[GCKCastContext sharedInstance] createCastContainerControllerForViewController:navigationController]; castContainerVC.miniMediaControlsItemEnabled = YES; self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; self.window.rootViewController = castContainerVC; [self.window makeKeyAndVisible]; ... }
var castControlBarsEnabled: Bool { set(enabled) { if let castContainerVC = self.window?.rootViewController as? GCKUICastContainerViewController { castContainerVC.miniMediaControlsItemEnabled = enabled } else { print("GCKUICastContainerViewController is not correctly configured") } } get { if let castContainerVC = self.window?.rootViewController as? GCKUICastContainerViewController { return castContainerVC.miniMediaControlsItemEnabled } else { print("GCKUICastContainerViewController is not correctly configured") return false } } }
AppDelegate.h
@interface AppDelegate : UIResponder <UIApplicationDelegate> @property (nonatomic, strong) UIWindow *window; @property (nonatomic, assign) BOOL castControlBarsEnabled; @end
AppDelegate.m
@implementation AppDelegate ... - (void)setCastControlBarsEnabled:(BOOL)notificationsEnabled { GCKUICastContainerViewController *castContainerVC; castContainerVC = (GCKUICastContainerViewController *)self.window.rootViewController; castContainerVC.miniMediaControlsItemEnabled = notificationsEnabled; } - (BOOL)castControlBarsEnabled { GCKUICastContainerViewController *castContainerVC; castContainerVC = (GCKUICastContainerViewController *)self.window.rootViewController; return castContainerVC.miniMediaControlsItemEnabled; } ... @end
In vorhandenen Ansichts-Controller einbetten
Die zweite Möglichkeit besteht darin, den Mini-Controller direkt zu Ihrer vorhandenen Ansicht hinzuzufügen.
für die Steuerung durch
createMiniMediaControlsViewController
zum Erstellen eines
GCKUIMiniMediaControlsViewController
und fügen sie dann als untergeordnete Ansicht zum Controller der Containeransicht hinzu.
Richten Sie den Ansichts-Controller im App-Delegaten ein:
<ph type="x-smartling-placeholder">func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { ... GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true window?.clipsToBounds = true let rootContainerVC = (window?.rootViewController as? RootContainerViewController) rootContainerVC?.miniMediaControlsViewEnabled = true ... return true }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES; self.window.clipsToBounds = YES; RootContainerViewController *rootContainerVC; rootContainerVC = (RootContainerViewController *)self.window.rootViewController; rootContainerVC.miniMediaControlsViewEnabled = YES; ... return YES; }
Erstellen Sie in Ihrem Root View Controller einen GCKUIMiniMediaControlsViewController
.
und fügen Sie sie dem Container View Controller als untergeordnete Ansicht hinzu:
let kCastControlBarsAnimationDuration: TimeInterval = 0.20 @objc(RootContainerViewController) class RootContainerViewController: UIViewController, GCKUIMiniMediaControlsViewControllerDelegate { @IBOutlet weak private var _miniMediaControlsContainerView: UIView! @IBOutlet weak private var _miniMediaControlsHeightConstraint: NSLayoutConstraint! private var miniMediaControlsViewController: GCKUIMiniMediaControlsViewController! var miniMediaControlsViewEnabled = false { didSet { if self.isViewLoaded { self.updateControlBarsVisibility() } } } var overriddenNavigationController: UINavigationController? override var navigationController: UINavigationController? { get { return overriddenNavigationController } set { overriddenNavigationController = newValue } } var miniMediaControlsItemEnabled = false override func viewDidLoad() { super.viewDidLoad() let castContext = GCKCastContext.sharedInstance() self.miniMediaControlsViewController = castContext.createMiniMediaControlsViewController() self.miniMediaControlsViewController.delegate = self self.updateControlBarsVisibility() self.installViewController(self.miniMediaControlsViewController, inContainerView: self._miniMediaControlsContainerView) } func updateControlBarsVisibility() { if self.miniMediaControlsViewEnabled && self.miniMediaControlsViewController.active { self._miniMediaControlsHeightConstraint.constant = self.miniMediaControlsViewController.minHeight self.view.bringSubview(toFront: self._miniMediaControlsContainerView) } else { self._miniMediaControlsHeightConstraint.constant = 0 } UIView.animate(withDuration: kCastControlBarsAnimationDuration, animations: {() -> Void in self.view.layoutIfNeeded() }) self.view.setNeedsLayout() } func installViewController(_ viewController: UIViewController?, inContainerView containerView: UIView) { if let viewController = viewController { self.addChildViewController(viewController) viewController.view.frame = containerView.bounds containerView.addSubview(viewController.view) viewController.didMove(toParentViewController: self) } } func uninstallViewController(_ viewController: UIViewController) { viewController.willMove(toParentViewController: nil) viewController.view.removeFromSuperview() viewController.removeFromParentViewController() } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "NavigationVCEmbedSegue" { self.navigationController = (segue.destination as? UINavigationController) } } ...
RootContainerViewController.h
static const NSTimeInterval kCastControlBarsAnimationDuration = 0.20; @interface RootContainerViewController () <GCKUIMiniMediaControlsViewControllerDelegate> { __weak IBOutlet UIView *_miniMediaControlsContainerView; __weak IBOutlet NSLayoutConstraint *_miniMediaControlsHeightConstraint; GCKUIMiniMediaControlsViewController *_miniMediaControlsViewController; } @property(nonatomic, weak, readwrite) UINavigationController *navigationController; @property(nonatomic, assign, readwrite) BOOL miniMediaControlsViewEnabled; @property(nonatomic, assign, readwrite) BOOL miniMediaControlsItemEnabled; @end
RootContainerViewController.m
@implementation RootContainerViewController - (void)viewDidLoad { [super viewDidLoad]; GCKCastContext *castContext = [GCKCastContext sharedInstance]; _miniMediaControlsViewController = [castContext createMiniMediaControlsViewController]; _miniMediaControlsViewController.delegate = self; [self updateControlBarsVisibility]; [self installViewController:_miniMediaControlsViewController inContainerView:_miniMediaControlsContainerView]; } - (void)setMiniMediaControlsViewEnabled:(BOOL)miniMediaControlsViewEnabled { _miniMediaControlsViewEnabled = miniMediaControlsViewEnabled; if (self.isViewLoaded) { [self updateControlBarsVisibility]; } } - (void)updateControlBarsVisibility { if (self.miniMediaControlsViewEnabled && _miniMediaControlsViewController.active) { _miniMediaControlsHeightConstraint.constant = _miniMediaControlsViewController.minHeight; [self.view bringSubviewToFront:_miniMediaControlsContainerView]; } else { _miniMediaControlsHeightConstraint.constant = 0; } [UIView animateWithDuration:kCastControlBarsAnimationDuration animations:^{ [self.view layoutIfNeeded]; }]; [self.view setNeedsLayout]; } - (void)installViewController:(UIViewController *)viewController inContainerView:(UIView *)containerView { if (viewController) { [self addChildViewController:viewController]; viewController.view.frame = containerView.bounds; [containerView addSubview:viewController.view]; [viewController didMoveToParentViewController:self]; } } - (void)uninstallViewController:(UIViewController *)viewController { [viewController willMoveToParentViewController:nil]; [viewController.view removeFromSuperview]; [viewController removeFromParentViewController]; } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"NavigationVCEmbedSegue"]) { self.navigationController = (UINavigationController *)segue.destinationViewController; } } ... @end
Die
GCKUIMiniMediaControlsViewControllerDelegate
teilt dem Host View Controller mit, wann der Mini-Controller sichtbar sein soll:
func miniMediaControlsViewController(_: GCKUIMiniMediaControlsViewController, shouldAppear _: Bool) { updateControlBarsVisibility() }
- (void)miniMediaControlsViewController: (GCKUIMiniMediaControlsViewController *)miniMediaControlsViewController shouldAppear:(BOOL)shouldAppear { [self updateControlBarsVisibility]; }
Maximierten Controller hinzufügen
Die Checkliste für das Google Cast-Design setzt voraus, dass eine Absender-App eine maximierte Controller für die gestreamten Medien. Der erweiterte Controller ist eine Vollbildversion von den Mini-Controller.
Der erweiterte Controller ermöglicht eine Vollbildansicht mit vollständiger Steuerung des für die Remote-Medienwiedergabe. Diese Ansicht sollte es einer Streaming-App ermöglichen, alle überschaubarer Aspekt einer Übertragungssitzung, mit Ausnahme der Web Receiver-Lautstärke und den Sitzungslebenszyklus (Verbindung verbinden/beenden). Außerdem bietet es alle Statusinformationen zur Mediensitzung (Artwork, Titel, Untertitel usw.) weiter).
Die Funktionalität dieser Ansicht wird durch den
GCKUIExpandedMediaControlsViewController
.
Zunächst musst du den erweiterten Standard-Controller in der Kontext zu streamen. Ändern Sie den App-Delegaten, um den standardmäßigen erweiterten Controller zu aktivieren:
<ph type="x-smartling-placeholder">func applicationDidFinishLaunching(_ application: UIApplication) { .. GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true ... }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES; .. }
Fügen Sie dem Ansichts-Controller den folgenden Code hinzu, um den erweiterten Controller zu laden Der Nutzer beginnt mit dem Streamen eines Videos:
<ph type="x-smartling-placeholder">func playSelectedItemRemotely() { GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls() ... // Load your media sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInformation) }
- (void)playSelectedItemRemotely { [[GCKCastContext sharedInstance] presentDefaultExpandedMediaControls]; ... // Load your media [self.sessionManager.currentSession.remoteMediaClient loadMedia:mediaInformation]; }
Der erweiterte Controller wird auch automatisch gestartet, wenn der Nutzer tippt auf den Mini-Controller.
Wenn die Sender-App einen Video- oder Audio-Livestream wiedergibt, gibt das SDK zeigt automatisch eine Wiedergabe-/Stopp-Schaltfläche anstelle der Wiedergabe-/Pause-Schaltfläche an. im maximierten Controller.
Siehe Benutzerdefinierte Stile auf Ihr iOS-Gerät anwenden App , wie Ihre Absender-App das Aussehen der Cast-Widgets konfigurieren kann.
Lautstärkeregelung
Das Cast-Framework verwaltet automatisch das Volume für die Absender-App. Die
wird das Framework automatisch mit dem Web Receiver-Volume für die
UI-Widgets bereitstellen. Um einen von der App bereitgestellten Schieberegler zu synchronisieren, verwenden Sie
GCKUIDeviceVolumeController
Lautstärkeregelung mit physischer Taste
Mit den Lautstärketasten am Sendergerät kann die
Lautstärke der Übertragungssitzung auf dem Web Receiver über die
physicalVolumeButtonsWillControlDeviceVolume
-Flag im
GCKCastOptions
,
die auf der
GCKCastContext
let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID) let options = GCKCastOptions(discoveryCriteria: criteria) options.physicalVolumeButtonsWillControlDeviceVolume = true GCKCastContext.setSharedInstanceWith(options)
GCKDiscoveryCriteria *criteria = [[GCKDiscoveryCriteria alloc] initWithApplicationID:kReceiverAppID]; GCKCastOptions *options = [[GCKCastOptions alloc] initWithDiscoveryCriteria :criteria]; options.physicalVolumeButtonsWillControlDeviceVolume = YES; [GCKCastContext setSharedInstanceWithOptions:options];
Fehler verarbeiten
Absender-Apps müssen alle Fehlerrückrufe verarbeiten und entscheiden, die beste Reaktion für jede Phase des Cast-Lebenszyklus. Die App kann Folgendes anzeigen: wird dem Nutzer eine Fehlermeldung angezeigt. Andernfalls kann er das Streaming beenden.
Logging
GCKLogger
ist ein Singleton-Element, das vom Framework für das Logging verwendet wird. Verwenden Sie die Methode
GCKLoggerDelegate
um die Verarbeitung von Logeinträgen anzupassen.
Mit dem GCKLogger
erzeugt das SDK eine Logging-Ausgabe in Form von „Debug“.
Meldungen, Fehler und Warnungen. Diese Logeinträge unterstützen Sie bei der Fehlerbehebung und sind nützlich
zur Fehlerbehebung und Identifizierung von Problemen. Die Logausgabe ist standardmäßig
aber durch Zuweisen einer GCKLoggerDelegate
kann die Absender-App
vom SDK aus und protokolliert sie in der Systemkonsole.
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, GCKLoggerDelegate { let kReceiverAppID = kGCKDefaultMediaReceiverApplicationID let kDebugLoggingEnabled = true var window: UIWindow? func applicationDidFinishLaunching(_ application: UIApplication) { ... // Enable logger. GCKLogger.sharedInstance().delegate = self ... } // MARK: - GCKLoggerDelegate func logMessage(_ message: String, at level: GCKLoggerLevel, fromFunction function: String, location: String) { if (kDebugLoggingEnabled) { print(function + " - " + message) } } }
AppDelegate.h
@interface AppDelegate () <GCKLoggerDelegate> @end
AppDelegate.m
@implementation AppDelegate static NSString *const kReceiverAppID = @"AABBCCDD"; static const BOOL kDebugLoggingEnabled = YES; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... // Enable logger. [GCKLogger sharedInstance].delegate = self; ... return YES; } ... #pragma mark - GCKLoggerDelegate - (void)logMessage:(NSString *)message atLevel:(GCKLoggerLevel)level fromFunction:(NSString *)function location:(NSString *)location { if (kDebugLoggingEnabled) { NSLog(@"%@ - %@, %@", function, message, location); } } @end
Um auch Debug- und ausführliche Meldungen zu aktivieren, fügen Sie diese Zeile in den Code ein, Festlegen des Bevollmächtigten (siehe oben):
<ph type="x-smartling-placeholder">let filter = GCKLoggerFilter.init() filter.minimumLevel = GCKLoggerLevel.verbose GCKLogger.sharedInstance().filter = filter
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init]; [filter setMinimumLevel:GCKLoggerLevelVerbose]; [GCKLogger sharedInstance].filter = filter;
Sie können auch die von
GCKLogger
Legen Sie die minimale Logging-Ebene pro Klasse fest. Beispiel:
let filter = GCKLoggerFilter.init() filter.setLoggingLevel(GCKLoggerLevel.verbose, forClasses: ["GCKUICastButton", "GCKUIImageCache", "NSMutableDictionary"]) GCKLogger.sharedInstance().filter = filter
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init]; [filter setLoggingLevel:GCKLoggerLevelVerbose forClasses:@[@"GCKUICastButton", @"GCKUIImageCache", @"NSMutableDictionary" ]]; [GCKLogger sharedInstance].filter = filter;
Die Klassennamen können entweder Literalnamen oder glob-Muster sein, z. B.
GCKUI\*
und GCK\*Session
.