Z tego przewodnika dla programistów dowiesz się, jak dodać obsługę Google Cast na urządzeniach z iOS. aplikacji nadawcy, używając pakietu SDK nadawcy na iOS.
Urządzenie mobilne lub laptop jest nadawcą, który steruje odtwarzaniem. Urządzenie Google Cast to odbiornik, który wyświetla treści na telewizorze.
Platforma nadawcy odnosi się do pliku binarnego biblioteki klas Cast zasoby dostępne w czasie działania u nadawcy. aplikację nadawcy lub aplikację Cast. odnosi się do aplikacji również uruchomionej u nadawcy. aplikacji Web Receiver odnosi się do aplikacji HTML uruchomionej na odbiorniku internetowym.
Platforma nadawcy korzysta z asynchronicznego projektu wywołania zwrotnego do informowania nadawcy możesz w niej używać zdarzeń i przełączać się między różnymi stanami aplikacji Cast. cyklu.
Przepływ aplikacji
Poniższe kroki opisują typowy proces wysyłania wysokiego poziomu u nadawcy Aplikacja na iOS:
- Platforma Cast uruchamia się
GCKDiscoveryManager
na podstawie właściwości podanych wGCKCastOptions
do rozpocząć skanowanie w poszukiwaniu urządzeń. - Gdy użytkownik kliknie przycisk Cast, platforma wyświetla moduł Cast z listą wykrytych urządzeń przesyłających.
- Gdy użytkownik wybierze urządzenie przesyłające, platforma próbuje uruchomić aplikacja Web Receiver na urządzeniu przesyłającym.
- Platforma wywołuje wywołania zwrotne w aplikacji nadawcy, aby potwierdzić, że Aplikacja Web Receiver została uruchomiona.
- Platforma tworzy kanał komunikacji między nadawcą a aplikacji odbiornika internetowego.
- Platforma używa kanału komunikacyjnego do wczytywania mediów i sterowania nimi na odbiorniku internetowym.
- Platforma synchronizuje stan odtwarzania multimediów między nadawcą i Odbiornik internetowy: gdy użytkownik wykonuje działania w interfejsie nadawcy, platforma przekazuje żądania sterowania multimediami do odbiornika internetowego, wysyła aktualizacje stanu multimediów, platforma aktualizuje stan interfejsu użytkownika nadawcy.
- Gdy użytkownik kliknie przycisk Cast, by odłączyć urządzenie przesyłające, platforma odłączy aplikację wysyłającą od odbiornika internetowego.
Aby rozwiązać problemy z nadawcą, musisz włączyć rejestrowanie.
Pełną listę wszystkich klas, metod i zdarzeń w Google Cast platforma iOS, zobacz interfejs Google Cast iOS API Plik referencyjny. Sekcje poniżej do integracji Cast z aplikacją na iOS.
Metody nawiązywania połączeń z wątku głównego
Inicjowanie kontekstu przesyłania
Platforma Cast ma globalny obiekt typu singleton,
GCKCastContext
, czyli
koordynuje wszystkie działania w ramach platformy. Ten obiekt musi zostać zainicjowany
na wczesnym etapie cyklu życia aplikacji, zwykle
-[application:didFinishLaunchingWithOptions:]
metody przekazywania dostępu do aplikacji, więc
że automatyczne wznowienie sesji po ponownym uruchomieniu aplikacji nadawcy może aktywować się prawidłowo.
GCKCastOptions
podczas inicjowania GCKCastContext
należy podać obiekt.
Ta klasa zawiera opcje, które mają wpływ na działanie platformy. Najbardziej
ważnym z nich jest identyfikator aplikacji odbiornika internetowego, który służy do filtrowania
w wynikach wykrywania i uruchamiać aplikację Web Receiver po rozpoczęciu sesji przesyłania.
rozpoczęto.
Możesz też skorzystać z metody -[application:didFinishLaunchingWithOptions:]
aby skonfigurować przedstawiciela logowania, który będzie odbierał komunikaty logowania z platformy.
Mogą one być przydatne podczas debugowania i rozwiązywania problemów.
@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
Widżety Cast – UX
Te widżety są zgodne z projektem Cast w pakiecie SDK na iOS. Lista kontrolna:
Nakładka wprowadzająca: Klasa
GCKCastContext
ma metodę,presentCastInstructionsViewControllerOnceWithCastButton
, może posłużyć do wyróżnienia przycisku Cast przy pierwszym odbiorniku internetowym jest dostępna. Aplikacja nadawcy może dostosować tekst i pozycję tytułu tekst i przycisk Zamknij.Przycisk przesyłania: Od pakietu SDK Cast na iOS 4.6.0 przycisk przesyłania jest zawsze widoczny. gdy urządzenie wysyłające jest połączone z Wi-Fi. za pierwszym razem, gdy użytkownik kliknie reklamę. przycisk Cast po uruchomieniu aplikacji, okno uprawnień więc użytkownik może przyznać aplikacji dostęp przez sieć lokalną do urządzeń w sieci. Następnie, gdy użytkownik kliknie przycisk przesyłania, pojawi się okno z listą wykrytych urządzeń. Gdy użytkownik kliknie reklamę na przycisku przesyłania, gdy urządzenie jest podłączone, wyświetla metadane multimediów (np. tytuł, nazwa studia nagraniowego i miniatura). obraz) lub pozwala użytkownikowi odłączyć się od urządzenia przesyłającego. Gdy użytkownik dotknij przycisku przesyłania, gdy nie ma dostępnych urządzeń, zostanie wyświetlona z informacją o przyczynach, dla których urządzenia nie zostały znalezione i sposobach ich rozwiązywania.
Minikontroler: Gdy użytkownik przesyła treści i opuszcza bieżące strony treści lub rozszerzenia kontrolera na inny ekran w aplikacji nadawcy, na dole ekranu wyświetlany jest minikontroler, aby użytkownik mógł przeglądać metadane aktualnie przesyłanych multimediów i sterować odtwarzaniem.
Rozszerzony kontroler: Gdy użytkownik przesyła treści, jeśli kliknie powiadomienie o multimediach lub mini kontroler, pojawi się rozwinięty kontroler, który wyświetla z odtwarzanymi metadanymi i zawiera kilka przycisków do sterowania odtwarzania multimediów.
Dodaj przycisk Cast
Platforma udostępnia komponent przycisku Cast jako podklasę UIButton
. Może
zostaną dodane do paska tytułu aplikacji przez owinięcie go w znacznik UIBarButtonItem
. Typowa
Podklasa UIViewController
może instalować przycisk Cast w ten sposób:
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];
Domyślnie kliknięcie przycisku powoduje otwarcie okna przesyłania platformy.
GCKUICastButton
można również dodawać bezpośrednio do scenorysu.
Skonfiguruj wykrywanie urządzeń
W ramach platformy wykrywanie urządzeń odbywa się automatycznie. Nie ma potrzeby bezpośrednio rozpocząć lub zatrzymać proces wykrywania, chyba że wdrożysz niestandardowy interfejs użytkownika.
Odkrywanie w ramach platformy jest zarządzane przez klasę
GCKDiscoveryManager
,
, która jest właściwością
GCKCastContext
udostępnia domyślny komponent okna przesyłania
do wyboru urządzenia i
. Lista urządzeń jest uporządkowana leksykograficznie według nazwy przyjaznej dla urządzeń.
Jak działa zarządzanie sesjami
SDK Cast wprowadza pojęcie sesji przesyłania: instytucja łącząca etapy łączenia się z urządzeniem, uruchamiania (lub łączenia) z internetem Aplikacja odbiornika, łączenie się z nią i inicjowanie kanału sterowania multimediami. Zobacz odbiornik internetowy Przewodnik po cyklu życia zgłoszenia , by dowiedzieć się więcej o sesjach przesyłania i cyklu życia odbiornika internetowego.
Sesjami zarządza zajęcia
GCKSessionManager
,
, która jest właściwością
GCKCastContext
Poszczególne sesje są reprezentowane przez podklasy klasy
GCKSession
: na przykład
GCKCastSession
reprezentuje sesje z urządzeniami przesyłającymi. Możesz uzyskać dostęp do obecnie aktywnej funkcji przesyłania
sesja (jeśli istnieje) jako właściwość currentCastSession
elementu GCKSessionManager
.
GCKSessionManagerListener
może służyć do monitorowania zdarzeń sesji, takich jak utworzenie sesji,
zawieszenia, wznowienia i zamknięcia. Platforma automatycznie zawiesza się
sesje, gdy aplikacja nadawcy działa w tle i próbuje ją wznowić
gdy aplikacja wróci na pierwszy plan (lub zostanie ponownie uruchomiona po
nieprawidłowe/nagłe zakończenie działania aplikacji podczas trwania sesji).
Jeśli używane jest okno Przesyłaj, sesje są tworzone i wyłączane
automatycznie w odpowiedzi na gesty użytkownika. W przeciwnym razie aplikacja może się uruchamiać i kończyć,
za pomocą metod
GCKSessionManager
czy aplikacja musi wykonywać specjalne przetwarzanie w odpowiedzi na cykl życia sesji.
zdarzeń, może zarejestrować co najmniej jedną instancję GCKSessionManagerListener
z
GCKSessionManager
. GCKSessionManagerListener
to protokół, który określa
dla takich zdarzeń, jak początek sesji, koniec sesji itp.
Przenoszenie strumienia
Zachowywanie stanu sesji jest podstawą transferu, gdzie użytkownicy mogą przenosić istniejące strumienie audio i wideo między urządzeniami, używając poleceń głosowych. Google Home Aplikacja lub inteligentne ekrany. Multimedia przestaje się odtwarzać na jednym urządzeniu (źródle) i kontynuuje na innym ( miejsce docelowe). Każde urządzenie przesyłające z najnowszą wersją oprogramowania może służyć jako źródło lub miejsce docelowe w przesyłanie strumienia.
Aby pobrać nowe urządzenie docelowe podczas przenoszenia transmisji, skorzystaj z
GCKCastSession#device
usługi w okresie
[sessionManager:didResumeCastSession:]
oddzwanianie.
Zobacz Przesyłanie strumienia w internetowym odbiorniku .
Automatyczne ponowne łączenie
Platforma Cast dodaje logikę ponownego połączenia, aby automatycznie obsługiwać ponowne łączenie w wielu subtelnych rogach, takich jak:
- Odzyskanie połączenia po tymczasowej utracie sieci Wi-Fi
- Wypoczynek po uśpieniu urządzenia
- Przywracanie aplikacji w tle
- Przywracanie systemu w przypadku awarii aplikacji
Jak działa sterowanie multimediami
Jeśli sesja przesyłania została ustanowiona za pomocą odbiornika internetowego, który obsługuje multimedia
przestrzeni nazw, instancję
GCKRemoteMediaClient
zostanie utworzona automatycznie przez platformę; można uzyskać do niego dostęp jako
remoteMediaClient
właściwości
GCKCastSession
instancji.
Wszystkie metody w GCKRemoteMediaClient
, które wysyłają żądania do odbiornika internetowego
zwróci błąd
GCKRequest
obiekt, który
można użyć do śledzenia żądania. O
GCKRequestDelegate
można przypisać do tego obiektu, aby otrzymywać powiadomienia o
wyniku operacji.
Oczekiwane jest, że wystąpienie GCKRemoteMediaClient
mogą być współdzielone przez wiele części aplikacji oraz niektóre wewnętrzne komponenty
platformy, takiej jak okno Cast i minielementy sterujące multimediami,
instancji. Dlatego GCKRemoteMediaClient
obsługuje rejestrację wielu
GCKRemoteMediaClientListener
Ustawianie metadanych multimediów
GCKMediaMetadata
klasa reprezentuje informacje o elemencie multimedialnym, który chcesz przesyłać. Poniżej
tworzy nowe wystąpienie GCKMediaMetadata
filmu i ustawia tytuł,
podtytuł, nazwę studia nagraniowego i 2 obrazy.
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]];
Zapoznaj się z sekcją Wybór obrazów i Buforowanie o używaniu obrazów z metadanymi multimediów.
Wczytaj multimedia
Aby wczytać element multimedialny, utwórz
GCKMediaInformation
przy użyciu metadanych multimediów. Następnie pobierz bieżącą
GCKCastSession
i
użyj jego
GCKRemoteMediaClient
aby wczytać multimedia do aplikacji odbiornika. Następnie możesz użyć GCKRemoteMediaClient
do sterowania aplikacją odtwarzacza działającej na odbiorniku, np. w celu odtwarzania,
wstrzymać i zatrzymać.
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; }
Zobacz też sekcję na temat za pomocą ścieżek multimedialnych.
Format filmu 4K
Aby określić format filmu, użyj właściwości videoInfo
GCKMediaStatus
.
aby pobrać bieżącą instancję
GCKVideoInfo
Ta instancja zawiera typ formatu telewizora HDR oraz wysokość i szerokość w
pikseli. Warianty formatu 4K są wskazane we właściwości hdrType
za pomocą wyliczenia
wartości GCKVideoInfoHDRType
.
Dodaj minikontrolery
Zgodnie z projektem obsady Lista kontrolna, aplikacja nadawcy powinna zapewniać trwałą kontrolę nazywaną minimalna kontroler który powinien się pojawiać, gdy użytkownik opuści bieżącą stronę z treścią. Minikontroler zapewnia natychmiastowy dostęp i wyświetla przypomnienia bieżącej sesji przesyłania.
Platforma Cast zawiera pasek sterowania,
GCKUIMiniMediaControlsViewController
,
które można dodawać do scen, w których chcesz pokazać minikontroler.
Gdy aplikacja nadawcy odtwarza transmisję na żywo wideo lub audio, pakiet SDK automatycznie wyświetla przycisk odtwarzania/zatrzymania w miejscu przycisku odtwarzania/wstrzymania. na minikontrolerze.
Zapoznaj się z artykułem Dostosowywanie interfejsu nadawcy w iOS, aby dowiedzieć się, jak w aplikacji nadawcy może skonfigurować wygląd widżetów Cast.
Minikontroler można dodać do aplikacji wysyłającej na 2 sposoby:
- Pozwól platformie Cast zarządzać układem minikontrolera przez opakowanie z dotychczasowym kontrolerem widoku danych.
- Zarządzaj układem widżetu minikontrolera, dodając go do swojego istniejącego kontrolera widoku, udostępniając widok podrzędny w scenorysie.
Zawijaj za pomocą kontrolera GCKUICastContainerViewController
Pierwszym z nich jest użycie
GCKUICastContainerViewController
które otacza inny kontroler widoku danych i dodaje do niego tag
GCKUIMiniMediaControlsViewController
na dole. Takie podejście jest ograniczone, ponieważ nie można dostosowywać
animacji i nie można skonfigurować zachowania kontrolera widoku kontenera.
Pierwszy sposób polega zwykle na
Metoda -[application:didFinishLaunchingWithOptions:]
na potrzeby przekazywania dostępu do aplikacji:
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
Umieść w istniejącym kontrolerze widoku
Drugi sposób to dodanie minikontrolera bezpośrednio do dotychczasowego widoku.
za pomocą
createMiniMediaControlsViewController
aby utworzyć
GCKUIMiniMediaControlsViewController
a potem dodać ją do kontrolera widoku kontenera jako widok podrzędny.
Skonfiguruj kontroler widoku w przekazywaniu dostępu do aplikacji:
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; }
W kontrolerze widoku głównego utwórz GCKUIMiniMediaControlsViewController
i dodaj ją do kontrolera widoku kontenera jako widok podrzędny:
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
GCKUIMiniMediaControlsViewControllerDelegate
informuje kontroler widoku hosta, kiedy minikontroler powinien być widoczny:
func miniMediaControlsViewController(_: GCKUIMiniMediaControlsViewController, shouldAppear _: Bool) { updateControlBarsVisibility() }
- (void)miniMediaControlsViewController: (GCKUIMiniMediaControlsViewController *)miniMediaControlsViewController shouldAppear:(BOOL)shouldAppear { [self updateControlBarsVisibility]; }
Dodaj rozszerzony kontroler
Lista kontrolna projektowania Google Cast wymaga, by aplikacja wysyłająca udostępniała rozwinięty obraz kontroler dla przesyłanych multimediów. Rozwinięty kontroler to pełnoekranowa wersja na minikontroler.
Rozwinięty kontroler umożliwia oglądanie na pełnym ekranie, co zapewnia pełną kontrolę zdalnego odtwarzania multimediów. Ten widok powinien umożliwiać aplikacji przesyłającej zarządzanie łatwy do zarządzania aspekt sesji przesyłania, z wyjątkiem głośności odbiornika internetowego. kontrolę i cykl życia sesji (połączenie/zatrzymanie przesyłania). Zapewnia też wszystkie informacje o stanie sesji multimediów (grafika, tytuł, podtytuł itp.) ).
Funkcjonalność tego widoku jest implementowana przez
GCKUIExpandedMediaControlsViewController
zajęcia.
Najpierw musisz włączyć domyślny rozwinięty kontroler w kontekst przesyłania. Zmień uprawnienia dostępu do aplikacji, aby włączyć domyślny rozwinięty kontroler:
func applicationDidFinishLaunching(_ application: UIApplication) { .. GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true ... }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES; .. }
Dodaj ten kod do kontrolera widoku, aby wczytać rozwinięty kontroler gdy użytkownik rozpocznie przesyłanie filmu:
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]; }
Rozwinięty kontroler zostanie również uruchomiony automatycznie, gdy użytkownik dotknij minikontrolera.
Gdy aplikacja nadawcy odtwarza transmisję na żywo wideo lub audio, pakiet SDK automatycznie wyświetla przycisk odtwarzania/zatrzymania w miejscu przycisku odtwarzania/wstrzymania. w rozwiniętym kontrolerze.
Zobacz Stosowanie stylów niestandardowych do systemu iOS Aplikacja , aby dowiedzieć się, jak aplikacja nadawcy może skonfigurować wygląd widżetów Cast.
Sterowanie głośnością
Platforma Cast automatycznie zarządza głośnością aplikacji nadawcy.
automatycznie synchronizuje się z woluminem odbiornika internetowego dla
dostępnych widżetów interfejsu. Aby zsynchronizować suwak dostępny w aplikacji, użyj
GCKUIDeviceVolumeController
Regulacja głośności za pomocą przycisku fizycznego
Za pomocą fizycznych przycisków głośności na urządzeniu wysyłającym można zmienić
sesji przesyłania na odbiorniku internetowym za pomocą
flaga physicalVolumeButtonsWillControlDeviceVolume
na
GCKCastOptions
,
, która jest ustawiona na
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];
Obsługa błędów
Aplikacje nadawcy muszą obsługiwać wszystkie błędne wywołania zwrotne i podejmować decyzje, najlepszą odpowiedź na każdy etap cyklu życia Cast. Aplikacja może wyświetlać lub komunikat o błędzie. Może on też zakończyć sesję przesyłania.
Logowanie
GCKLogger
to singleton używany do logowania przez platformę. Użyj
GCKLoggerDelegate
aby dostosować sposób obsługi wiadomości dziennika.
Za pomocą interfejsu GCKLogger
pakiet SDK generuje dane wyjściowe rejestrowania w postaci debugowania
komunikatów, błędów i ostrzeżeń. Komunikaty te ułatwiają debugowanie i są przydatne
w celu ich rozwiązywania i wykrywania problemów. Domyślnie dane wyjściowe dziennika to
pominięto, ale dzięki przypisaniu funkcji GCKLoggerDelegate
aplikacja nadawcy może odbierać wiadomości
te komunikaty z pakietu SDK i rejestrujesz je w konsoli systemowej.
@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
Aby włączyć także debugowanie i komunikaty szczegółowe, dodaj ten wiersz do kodu za ustawianie przedstawiciela (przedstawionego wcześniej):
let filter = GCKLoggerFilter.init() filter.minimumLevel = GCKLoggerLevel.verbose GCKLogger.sharedInstance().filter = filter
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init]; [filter setMinimumLevel:GCKLoggerLevelVerbose]; [GCKLogger sharedInstance].filter = filter;
Możesz też filtrować komunikaty logu generowane przez
GCKLogger
Ustaw minimalny poziom logowania poszczególnych zajęć, na przykład:
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;
Nazwy klas mogą być nazwami literałowymi lub wzorcami glob, na przykład
GCKUI\*
i GCK\*Session
.