Zintegruj przesyłanie z aplikacją na iOS

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 w GCKCastOptions 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.

Swift
.
@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)
    }
  }
}
.
Objective-C

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:

Swift
.
let castButton = GCKUICastButton(frame: CGRect(x: 0, y: 0, width: 24, height: 24))
castButton.tintColor = UIColor.gray
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
.
Objective-C
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.

Swift
.
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))
.
Objective-C
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ć.

Swift
.
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
}
.
Objective-C
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:

Swift
.
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()

  ...
}
.
Objective-C
.
- (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];
  ...

}
.
Swift
.
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
    }
  }
}
.
Objective-C

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:

Swift
.
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
}
.
Objective-C
- (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:

Swift
.
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)
    }
  }

...
.
Objective-C

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:

Swift
.
  func miniMediaControlsViewController(_: GCKUIMiniMediaControlsViewController,
                                       shouldAppear _: Bool) {
    updateControlBarsVisibility()
  }
.
Objective-C
- (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:

Swift
.
func applicationDidFinishLaunching(_ application: UIApplication) {
  ..

  GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true

  ...
}
.
Objective-C
- (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:

Swift
.
func playSelectedItemRemotely() {
  GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()

  ...

  // Load your media
  sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInformation)
}
.
Objective-C
- (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

Swift
.
let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID)
let options = GCKCastOptions(discoveryCriteria: criteria)
options.physicalVolumeButtonsWillControlDeviceVolume = true
GCKCastContext.setSharedInstanceWith(options)
.
Objective-C
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.

Swift
.
@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)
    }
  }
}
.
Objective-C

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):

Swift
.
let filter = GCKLoggerFilter.init()
filter.minimumLevel = GCKLoggerLevel.verbose
GCKLogger.sharedInstance().filter = filter
.
Objective-C
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:

Swift
.
let filter = GCKLoggerFilter.init()
filter.setLoggingLevel(GCKLoggerLevel.verbose, forClasses: ["GCKUICastButton",
                                                            "GCKUIImageCache",
                                                            "NSMutableDictionary"])
GCKLogger.sharedInstance().filter = filter
.
Objective-C
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.