1. Przegląd

Z tego samouczka dowiesz się, jak zmodyfikować istniejącą aplikację wideo na iOS, aby przesyłać treści na urządzenie obsługujące Google Cast.
Co to jest Google Cast?
Google Cast umożliwia przesyłanie treści z urządzenia mobilnego na telewizor. Użytkownicy mogą wtedy używać urządzenia mobilnego jako pilota do odtwarzania multimediów na telewizorze.
Pakiet Google Cast SDK umożliwia rozszerzenie aplikacji o możliwość sterowania urządzeniami obsługującymi Google Cast (np. telewizorem lub systemem dźwiękowym). Pakiet Cast SDK umożliwia dodawanie niezbędnych komponentów interfejsu na podstawie listy kontrolnej projektu Google Cast.
Lista kontrolna projektu Google Cast została opracowana, aby zapewnić prostotę i przewidywalność korzystania z Cast na wszystkich obsługiwanych platformach.
Co będziemy tworzyć?
Po ukończeniu tego laboratorium uzyskasz aplikację wideo na iOS, która będzie mogła przesyłać filmy na urządzenie przesyłające Google Cast.
Czego się nauczysz
- Jak dodać pakiet Google Cast SDK do przykładowej aplikacji wideo.
- Jak dodać przycisk Cast, aby wybrać urządzenie przesyłające.
- Jak połączyć się z urządzeniem przesyłającym i uruchomić odbiornik multimediów.
- Jak przesyłać filmy
- Jak dodać do aplikacji minikontroler Cast.
- Jak dodać rozszerzony kontroler
- Jak wyświetlić nakładkę wprowadzającą
- Jak dostosować widżety Cast
- Jak zintegrować Cast Connect
Czego potrzebujesz
- Najnowsza wersja Xcode.
- Urządzenie mobilne z iOS 9 lub nowszym (lub symulator Xcode).
- kabel USB do transmisji danych, który umożliwia połączenie urządzenia mobilnego z komputerem deweloperskim (jeśli używasz urządzenia);
- Urządzenie przesyłające, np. Chromecast lub Android TV, skonfigurowane z dostępem do internetu.
- telewizor lub monitor z wejściem HDMI;
- Do przetestowania integracji Cast Connect wymagany jest Chromecast z Google TV, ale w pozostałej części Codelabu jest on opcjonalny. Jeśli nie masz takiego urządzenia, możesz pominąć krok Dodawanie obsługi Cast Connect pod koniec tego samouczka.
Doświadczenie
- Musisz mieć wcześniejszą wiedzę na temat tworzenia aplikacji na iOS.
- Musisz też mieć doświadczenie w oglądaniu telewizji.
Jak zamierzasz korzystać z tego samouczka?
Jak oceniasz swoje doświadczenie w tworzeniu aplikacji na iOS?
Jak oceniasz oglądanie telewizji?
2. Pobieranie przykładowego kodu
Możesz pobrać cały przykładowy kod na komputer...
i rozpakuj pobrany plik ZIP.
3. Uruchamianie przykładowej aplikacji

Najpierw zobaczmy, jak wygląda gotowa przykładowa aplikacja. Aplikacja jest podstawowym odtwarzaczem wideo. Użytkownik może wybrać film z listy, a następnie odtworzyć go lokalnie na urządzeniu lub przesłać na urządzenie przesyłające Google Cast.
Po pobraniu kodu wykonaj te instrukcje, aby otworzyć i uruchomić gotową przykładową aplikację w Xcode:
Najczęstsze pytania
Konfiguracja CocoaPods
Aby skonfigurować CocoaPods, otwórz konsolę i zainstaluj go za pomocą domyślnego środowiska Ruby dostępnego w systemie macOS:
sudo gem install cocoapods
Jeśli masz problemy, zapoznaj się z oficjalną dokumentacją, aby pobrać i zainstalować menedżera zależności.
Konfigurowanie projektu
- Otwórz terminal i przejdź do katalogu z codelabem.
- Zainstaluj zależności z pliku Podfile.
cd app-done pod update pod install
- Otwórz Xcode i kliknij Open another project... (Otwórz inny projekt…).
- Wybierz plik
CastVideos-ios.xcworkspacez katalogu
app-donew folderze z przykładowym kodem.
Uruchamianie aplikacji
Wybierz urządzenie docelowe i symulator, a następnie uruchom aplikację:

Po kilku sekundach powinna pojawić się aplikacja wideo.
Gdy pojawi się powiadomienie o akceptowaniu przychodzących połączeń sieciowych, kliknij „Zezwól”. Jeśli ta opcja nie zostanie zaakceptowana, ikona przesyłania nie będzie widoczna.

Kliknij przycisk Cast i wybierz urządzenie Google Cast.
Wybierz film i kliknij przycisk odtwarzania.
Film zacznie się odtwarzać na urządzeniu przesyłającym Google Cast.
Wyświetli się rozwinięty kontroler. Aby sterować odtwarzaniem, możesz użyć przycisku odtwarzania/wstrzymywania.
Wróć do listy filmów.
U dołu ekranu pojawi się minikontroler.

Kliknij przycisk wstrzymania na minikontrolerze, aby wstrzymać film na odbiorniku. Kliknij przycisk odtwarzania na minikontrolerze, aby ponownie odtworzyć film.
Kliknij przycisk Cast, aby zatrzymać przesyłanie na urządzenie przesyłające Google Cast.
4. Przygotowywanie projektu początkowego

Musimy dodać obsługę Google Cast do pobranej aplikacji startowej. W tym ćwiczeniu będziemy używać tych terminów związanych z Google Cast:
- aplikacja nadawcy jest uruchomiona na urządzeniu mobilnym lub laptopie,
- na urządzeniu przesyłającym działa aplikacja odbiornika;
Konfigurowanie projektu
Możesz teraz rozbudowywać projekt początkowy za pomocą Xcode:
- Otwórz terminal i przejdź do katalogu z codelabem.
- Zainstaluj zależności z pliku Podfile.
cd app-start pod update pod install
- Otwórz Xcode i kliknij Open another project... (Otwórz inny projekt…).
- Wybierz plik
CastVideos-ios.xcworkspacez katalogu
app-startw folderze z przykładowym kodem.
Projektowanie aplikacji
Aplikacja pobiera listę filmów z zdalnego serwera internetowego i udostępnia ją użytkownikowi. Użytkownicy mogą wybrać film, aby wyświetlić szczegóły lub odtworzyć go lokalnie na urządzeniu mobilnym.
Aplikacja składa się z 2 głównych kontrolerów widoku: MediaTableViewController i MediaViewController..
MediaTableViewController
Ten kontroler UITableViewController wyświetla listę filmów z obiektu MediaListModel. Lista filmów i powiązanych z nimi metadanych jest hostowana na serwerze zdalnym jako plik JSON. MediaListModel pobiera ten plik JSON i przetwarza go, aby utworzyć listę obiektów MediaItem.
Obiekt MediaItem modeluje film i powiązane z nim metadane, takie jak tytuł, opis, adres URL obrazu i adres URL strumienia.
MediaTableViewController tworzy instancję MediaListModel, a następnie rejestruje się jako MediaListModelDelegate, aby otrzymywać powiadomienia o pobraniu metadanych multimediów i móc wczytać widok tabeli.
Użytkownikowi wyświetla się lista miniatur filmów z krótkim opisem każdego z nich. Gdy element zostanie wybrany, odpowiednia wartość MediaItem zostanie przekazana do MediaViewController.
MediaViewController
Ten kontroler widoku wyświetla metadane dotyczące konkretnego filmu i umożliwia użytkownikowi odtworzenie go lokalnie na urządzeniu mobilnym.
Kontroler widoku zawiera LocalPlayerView, opcje sterowania multimediami i obszar tekstowy, w którym wyświetla się opis wybranego filmu. Odtwarzacz zajmuje górną część ekranu, pozostawiając miejsce na szczegółowy opis filmu poniżej. Użytkownik może odtwarzać i wstrzymywać lokalny film oraz przewijać go.
Najczęstsze pytania
5. Dodawanie przycisku Cast

Aplikacja obsługująca Cast wyświetla przycisk Cast w każdym kontrolerze widoku. Kliknięcie przycisku Cast powoduje wyświetlenie listy urządzeń obsługujących Cast, z której użytkownik może wybrać urządzenie. Jeśli użytkownik odtwarzał treści lokalnie na urządzeniu wysyłającym, wybranie urządzenia przesyłającego spowoduje rozpoczęcie lub wznowienie odtwarzania na tym urządzeniu. W dowolnym momencie sesji Cast użytkownik może kliknąć przycisk Cast i zatrzymać przesyłanie aplikacji na urządzenie przesyłające. Użytkownik musi mieć możliwość połączenia się z urządzeniem przesyłającym lub odłączenia od niego na dowolnym ekranie aplikacji, zgodnie z opisem w liście kontrolnej projektowania Google Cast.
Konfiguracja
Projekt początkowy wymaga tych samych zależności i konfiguracji Xcode co ukończona przykładowa aplikacja. Wróć do tej sekcji i wykonaj te same czynności, aby dodać GoogleCast.framework do projektu aplikacji początkowej.
Zdarzenie inicjujące
Platforma Cast ma globalny obiekt singleton GCKCastContext, który koordynuje wszystkie działania platformy. Ten obiekt musi zostać zainicjowany na wczesnym etapie cyklu życia aplikacji, zwykle w metodzie application(_:didFinishLaunchingWithOptions:) delegata aplikacji, aby można było prawidłowo uruchomić automatyczne wznawianie sesji po ponownym uruchomieniu aplikacji wysyłającej i rozpocząć skanowanie urządzeń.
Podczas inicjowania GCKCastContext należy podać obiekt GCKCastOptions. Ta klasa zawiera opcje, które wpływają na działanie platformy. Najważniejszy z nich to identyfikator aplikacji odbiornika, który służy do filtrowania wyników wykrywania urządzeń przesyłających i uruchamiania aplikacji odbiornika po rozpoczęciu sesji Cast.
Metoda application(_:didFinishLaunchingWithOptions:) to również dobre miejsce na skonfigurowanie delegata logowania, który będzie odbierać wiadomości logowania z platformy Cast. Mogą być przydatne podczas debugowania i rozwiązywania problemów.
Podczas tworzenia własnej aplikacji obsługującej Cast musisz zarejestrować się jako deweloper Cast, a następnie uzyskać identyfikator aplikacji. W tym samouczku użyjemy przykładowego identyfikatora aplikacji.
Dodaj ten kod do pliku AppDelegate.swift, aby zainicjować GCKCastContext za pomocą identyfikatora aplikacji z ustawień domyślnych użytkownika, i dodaj rejestrator dla platformy Google Cast:
import GoogleCast
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
fileprivate var enableSDKLogging = true
...
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let options = GCKCastOptions(discoveryCriteria: GCKDiscoveryCriteria(applicationID: kReceiverAppID))
options.physicalVolumeButtonsWillControlDeviceVolume = true
GCKCastContext.setSharedInstanceWith(options)
window?.clipsToBounds = true
setupCastLogging()
...
}
...
func setupCastLogging() {
let logFilter = GCKLoggerFilter()
let classesToLog = ["GCKDeviceScanner", "GCKDeviceProvider", "GCKDiscoveryManager", "GCKCastChannel",
"GCKMediaControlChannel", "GCKUICastButton", "GCKUIMediaController", "NSMutableDictionary"]
logFilter.setLoggingLevel(.verbose, forClasses: classesToLog)
GCKLogger.sharedInstance().filter = logFilter
GCKLogger.sharedInstance().delegate = self
}
}
...
// MARK: - GCKLoggerDelegate
extension AppDelegate: GCKLoggerDelegate {
func logMessage(_ message: String,
at _: GCKLoggerLevel,
fromFunction function: String,
location: String) {
if enableSDKLogging {
// Send SDK's log messages directly to the console.
print("\(location): \(function) - \(message)")
}
}
}
Przycisk Cast
Gdy GCKCastContext zostanie zainicjowany, musimy dodać przycisk Cast, aby umożliwić użytkownikowi wybór urządzenia przesyłającego. Pakiet Cast SDK udostępnia komponent przycisku Cast o nazwie GCKUICastButton jako podklasę UIButton. Możesz dodać go do paska tytułu aplikacji, umieszczając go w tagu UIBarButtonItem. Musimy dodać przycisk Cast do MediaTableViewController i MediaViewController.
Dodaj ten kod do plików MediaTableViewController.swift i MediaViewController.swift:
import GoogleCast
@objc(MediaTableViewController)
class MediaTableViewController: UITableViewController, GCKSessionManagerListener,
MediaListModelDelegate, GCKRequestDelegate {
private var castButton: GCKUICastButton!
...
override func viewDidLoad() {
print("MediaTableViewController - viewDidLoad")
super.viewDidLoad()
...
castButton = GCKUICastButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0),
width: CGFloat(24), height: CGFloat(24)))
// Overwrite the UIAppearance theme in the AppDelegate.
castButton.tintColor = UIColor.white
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
...
}
...
}
Następnie dodaj ten kod do pliku MediaViewController.swift:
import GoogleCast
@objc(MediaViewController)
class MediaViewController: UIViewController, GCKSessionManagerListener, GCKRemoteMediaClientListener,
LocalPlayerViewDelegate, GCKRequestDelegate {
private var castButton: GCKUICastButton!
...
override func viewDidLoad() {
super.viewDidLoad()
print("in MediaViewController viewDidLoad")
...
castButton = GCKUICastButton(frame: CGRect(x: CGFloat(0), y: CGFloat(0),
width: CGFloat(24), height: CGFloat(24)))
// Overwrite the UIAppearance theme in the AppDelegate.
castButton.tintColor = UIColor.white
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
...
}
...
}
Teraz uruchom aplikację. W pasku nawigacyjnym aplikacji powinien być widoczny przycisk Cast. Po kliknięciu go wyświetli się lista urządzeń przesyłających w sieci lokalnej. Wykrywanie urządzeń jest zarządzane automatycznie przez GCKCastContext. Wybierz urządzenie przesyłające, a na nim wczyta się przykładowa aplikacja odbiornika. Możesz przełączać się między aktywnością przeglądania a aktywnością lokalnego odtwarzacza, a stan przycisku Cast będzie synchronizowany.
Nie obsługujemy jeszcze odtwarzania multimediów, więc nie możesz jeszcze odtwarzać filmów na urządzeniu przesyłającym. Aby zatrzymać przesyłanie, kliknij przycisk Cast.
6. Przesyłanie treści wideo

Rozszerzymy przykładową aplikację, aby można było odtwarzać filmy zdalnie na urządzeniu przesyłającym. Aby to zrobić, musimy nasłuchiwać różnych zdarzeń generowanych przez platformę Cast.
Przesyłanie multimediów
Ogólnie rzecz biorąc, aby odtworzyć multimedia na urządzeniu przesyłającym, musisz wykonać te czynności:
- Utwórz obiekt
GCKMediaInformationz pakietu Cast SDK, który modeluje element multimedialny. - Użytkownik łączy się z urządzeniem przesyłającym, aby uruchomić aplikację odbiorcy.
- Włóż
GCKMediaInformationdo odbiornika i odtwórz treści. - śledzić stan multimediów,
- Wysyłanie poleceń odtwarzania do odbiornika na podstawie interakcji użytkownika.
Krok 1 polega na mapowaniu jednego obiektu na drugi. GCKMediaInformation to element, który jest zrozumiały dla pakietu Cast SDK, a MediaItem to hermetyzacja elementu multimedialnego w naszej aplikacji. Możemy łatwo zmapować MediaItem na GCKMediaInformation. Krok 2 został już wykonany w poprzedniej sekcji. Krok 3 jest łatwy do wykonania za pomocą pakietu Cast SDK.
Przykładowa aplikacja MediaViewController rozróżnia już odtwarzanie lokalne i zdalne za pomocą tego wyliczenia:
enum PlaybackMode: Int {
case none = 0
case local
case remote
}
private var playbackMode = PlaybackMode.none
W tym ćwiczeniu nie musisz dokładnie rozumieć, jak działa cała logika przykładowego odtwarzacza. Pamiętaj, że odtwarzacz multimediów w Twojej aplikacji będzie musiał zostać zmodyfikowany, aby w podobny sposób rozpoznawać 2 lokalizacje odtwarzania.
Obecnie odtwarzacz lokalny jest zawsze w stanie odtwarzania lokalnego, ponieważ nie ma jeszcze informacji o stanach przesyłania. Musimy zaktualizować interfejs na podstawie przejść stanu, które występują w platformie Cast. Jeśli na przykład rozpoczniemy przesyłanie, musimy zatrzymać lokalne odtwarzanie i wyłączyć niektóre elementy sterujące. Podobnie, jeśli w tym kontrolerze widoku zatrzymamy przesyłanie, musimy przejść do odtwarzania lokalnego. Aby to zrobić, musimy nasłuchiwać różnych zdarzeń generowanych przez platformę Cast.
Zarządzanie sesją przesyłania
W przypadku platformy Cast sesja Cast łączy w sobie czynności związane z łączeniem się z urządzeniem, uruchamianiem (lub dołączaniem), łączeniem się z aplikacją odbiornika i inicjowaniem kanału sterowania multimediami (w razie potrzeby). Kanał sterowania multimediami służy do wysyłania i odbierania wiadomości z odtwarzacza multimediów odbiornika.
Sesja Cast rozpocznie się automatycznie, gdy użytkownik wybierze urządzenie za pomocą przycisku Cast, i zakończy się automatycznie, gdy użytkownik się rozłączy. Ponowne łączenie z sesją odbiornika z powodu problemów z siecią jest również automatycznie obsługiwane przez platformę Cast.
Sesjami przesyłania zarządza GCKSessionManager, do którego można uzyskać dostęp za pomocą GCKCastContext.sharedInstance().sessionManager. Wywołania zwrotne GCKSessionManagerListener mogą służyć do monitorowania zdarzeń sesji, takich jak utworzenie, zawieszenie, wznowienie i zakończenie.
Najpierw musimy zarejestrować detektor sesji i zainicjować niektóre zmienne:
class MediaViewController: UIViewController, GCKSessionManagerListener,
GCKRemoteMediaClientListener, LocalPlayerViewDelegate, GCKRequestDelegate {
...
private var sessionManager: GCKSessionManager!
...
required init?(coder: NSCoder) {
super.init(coder: coder)
sessionManager = GCKCastContext.sharedInstance().sessionManager
...
}
override func viewWillAppear(_ animated: Bool) {
...
let hasConnectedSession: Bool = (sessionManager.hasConnectedSession())
if hasConnectedSession, (playbackMode != .remote) {
populateMediaInfo(false, playPosition: 0)
switchToRemotePlayback()
} else if sessionManager.currentSession == nil, (playbackMode != .local) {
switchToLocalPlayback()
}
sessionManager.add(self)
...
}
override func viewWillDisappear(_ animated: Bool) {
...
sessionManager.remove(self)
sessionManager.currentCastSession?.remoteMediaClient?.remove(self)
...
super.viewWillDisappear(animated)
}
func switchToLocalPlayback() {
...
sessionManager.currentCastSession?.remoteMediaClient?.remove(self)
...
}
func switchToRemotePlayback() {
...
sessionManager.currentCastSession?.remoteMediaClient?.add(self)
...
}
// MARK: - GCKSessionManagerListener
func sessionManager(_: GCKSessionManager, didStart session: GCKSession) {
print("MediaViewController: sessionManager didStartSession \(session)")
setQueueButtonVisible(true)
switchToRemotePlayback()
}
func sessionManager(_: GCKSessionManager, didResumeSession session: GCKSession) {
print("MediaViewController: sessionManager didResumeSession \(session)")
setQueueButtonVisible(true)
switchToRemotePlayback()
}
func sessionManager(_: GCKSessionManager, didEnd _: GCKSession, withError error: Error?) {
print("session ended with error: \(String(describing: error))")
let message = "The Casting session has ended.\n\(String(describing: error))"
if let window = appDelegate?.window {
Toast.displayMessage(message, for: 3, in: window)
}
setQueueButtonVisible(false)
switchToLocalPlayback()
}
func sessionManager(_: GCKSessionManager, didFailToStartSessionWithError error: Error?) {
if let error = error {
showAlert(withTitle: "Failed to start a session", message: error.localizedDescription)
}
setQueueButtonVisible(false)
}
func sessionManager(_: GCKSessionManager,
didFailToResumeSession _: GCKSession, withError _: Error?) {
if let window = UIApplication.shared.delegate?.window {
Toast.displayMessage("The Casting session could not be resumed.",
for: 3, in: window)
}
setQueueButtonVisible(false)
switchToLocalPlayback()
}
...
}
W MediaViewController chcemy otrzymywać powiadomienia o połączeniu z urządzeniem przesyłającym i rozłączeniu z nim, aby móc przełączać się między odtwarzaczem lokalnym a odtwarzaczem zdalnym. Pamiętaj, że połączenie może zostać przerwane nie tylko przez instancję aplikacji działającą na urządzeniu mobilnym, ale też przez inną instancję Twojej aplikacji (lub innej aplikacji) działającą na innym urządzeniu mobilnym.
Obecnie aktywna sesja jest dostępna jako GCKCastContext.sharedInstance().sessionManager.currentCastSession. Sesje są tworzone i zamykane automatycznie w odpowiedzi na gesty użytkownika w oknach przesyłania.
Wczytuję multimedia
W pakiecie Cast SDK klasa GCKRemoteMediaClient udostępnia zestaw wygodnych interfejsów API do zarządzania zdalnym odtwarzaniem multimediów na odbiorniku. W przypadku GCKCastSession obsługującego odtwarzanie multimediów pakiet SDK automatycznie utworzy instancję GCKRemoteMediaClient. Dostęp do niego można uzyskać jako właściwość remoteMediaClient instancji GCKCastSession.
Aby wczytać aktualnie wybrany film na odbiorniku, dodaj do pliku MediaViewController.swift ten kod:
@objc(MediaViewController)
class MediaViewController: UIViewController, GCKSessionManagerListener,
GCKRemoteMediaClientListener, LocalPlayerViewDelegate, GCKRequestDelegate {
...
@objc func playSelectedItemRemotely() {
loadSelectedItem(byAppending: false)
}
/**
* Loads the currently selected item in the current cast media session.
* @param appending If YES, the item is appended to the current queue if there
* is one. If NO, or if
* there is no queue, a new queue containing only the selected item is created.
*/
func loadSelectedItem(byAppending appending: Bool) {
print("enqueue item \(String(describing: mediaInfo))")
if let remoteMediaClient = sessionManager.currentCastSession?.remoteMediaClient {
let mediaQueueItemBuilder = GCKMediaQueueItemBuilder()
mediaQueueItemBuilder.mediaInformation = mediaInfo
mediaQueueItemBuilder.autoplay = true
mediaQueueItemBuilder.preloadTime = TimeInterval(UserDefaults.standard.integer(forKey: kPrefPreloadTime))
let mediaQueueItem = mediaQueueItemBuilder.build()
if appending {
let request = remoteMediaClient.queueInsert(mediaQueueItem, beforeItemWithID: kGCKMediaQueueInvalidItemID)
request.delegate = self
} else {
let queueDataBuilder = GCKMediaQueueDataBuilder(queueType: .generic)
queueDataBuilder.items = [mediaQueueItem]
queueDataBuilder.repeatMode = remoteMediaClient.mediaStatus?.queueRepeatMode ?? .off
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.mediaInformation = mediaInfo
mediaLoadRequestDataBuilder.queueData = queueDataBuilder.build()
let request = remoteMediaClient.loadMedia(with: mediaLoadRequestDataBuilder.build())
request.delegate = self
}
}
}
...
}
Teraz zaktualizuj różne istniejące metody, aby korzystały z logiki sesji Cast i obsługiwały odtwarzanie zdalne:
required init?(coder: NSCoder) {
super.init(coder: coder)
...
castMediaController = GCKUIMediaController()
...
}
func switchToLocalPlayback() {
print("switchToLocalPlayback")
if playbackMode == .local {
return
}
setQueueButtonVisible(false)
var playPosition: TimeInterval = 0
var paused: Bool = false
var ended: Bool = false
if playbackMode == .remote {
playPosition = castMediaController.lastKnownStreamPosition
paused = (castMediaController.lastKnownPlayerState == .paused)
ended = (castMediaController.lastKnownPlayerState == .idle)
print("last player state: \(castMediaController.lastKnownPlayerState), ended: \(ended)")
}
populateMediaInfo((!paused && !ended), playPosition: playPosition)
sessionManager.currentCastSession?.remoteMediaClient?.remove(self)
playbackMode = .local
}
func switchToRemotePlayback() {
print("switchToRemotePlayback; mediaInfo is \(String(describing: mediaInfo))")
if playbackMode == .remote {
return
}
// If we were playing locally, load the local media on the remote player
if playbackMode == .local, (_localPlayerView.playerState != .stopped), (mediaInfo != nil) {
print("loading media: \(String(describing: mediaInfo))")
let paused: Bool = (_localPlayerView.playerState == .paused)
let mediaQueueItemBuilder = GCKMediaQueueItemBuilder()
mediaQueueItemBuilder.mediaInformation = mediaInfo
mediaQueueItemBuilder.autoplay = !paused
mediaQueueItemBuilder.preloadTime = TimeInterval(UserDefaults.standard.integer(forKey: kPrefPreloadTime))
mediaQueueItemBuilder.startTime = _localPlayerView.streamPosition ?? 0
let mediaQueueItem = mediaQueueItemBuilder.build()
let queueDataBuilder = GCKMediaQueueDataBuilder(queueType: .generic)
queueDataBuilder.items = [mediaQueueItem]
queueDataBuilder.repeatMode = .off
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.queueData = queueDataBuilder.build()
let request = sessionManager.currentCastSession?.remoteMediaClient?.loadMedia(with: mediaLoadRequestDataBuilder.build())
request?.delegate = self
}
_localPlayerView.stop()
_localPlayerView.showSplashScreen()
setQueueButtonVisible(true)
sessionManager.currentCastSession?.remoteMediaClient?.add(self)
playbackMode = .remote
}
/* Play has been pressed in the LocalPlayerView. */
func continueAfterPlayButtonClicked() -> Bool {
let hasConnectedCastSession = sessionManager.hasConnectedCastSession
if mediaInfo != nil, hasConnectedCastSession() {
// Display an alert box to allow the user to add to queue or play
// immediately.
if actionSheet == nil {
actionSheet = ActionSheet(title: "Play Item", message: "Select an action", cancelButtonText: "Cancel")
actionSheet?.addAction(withTitle: "Play Now", target: self,
selector: #selector(playSelectedItemRemotely))
}
actionSheet?.present(in: self, sourceView: _localPlayerView)
return false
}
return true
}
Teraz uruchom aplikację na urządzeniu mobilnym. Połącz się z urządzeniem przesyłającym i zacznij odtwarzać film. Film powinien być odtwarzany na odbiorniku.
7. Mini kontroler
Lista kontrolna projektu Cast wymaga, aby wszystkie aplikacje Cast udostępniały mini kontroler, który pojawia się, gdy użytkownik opuści stronę z treścią. Miniodtwarzacz zapewnia natychmiastowy dostęp i widoczne przypomnienie o bieżącej sesji Cast.

Pakiet Cast SDK udostępnia pasek sterowania GCKUIMiniMediaControlsViewController, który można dodać do scen, w których chcesz wyświetlać trwałe elementy sterujące.
W aplikacji przykładowej użyjemy elementu GCKUICastContainerViewController, który otacza inny kontroler widoku i dodaje u dołu element GCKUIMiniMediaControlsViewController.
Zmodyfikuj plik AppDelegate.swift i dodaj ten kod dla warunku if useCastContainerViewController w tej metodzie:
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let appStoryboard = UIStoryboard(name: "Main", bundle: nil)
guard let navigationController = appStoryboard.instantiateViewController(withIdentifier: "MainNavigation")
as? UINavigationController else { return false }
let castContainerVC = GCKCastContext.sharedInstance().createCastContainerController(for: navigationController)
as GCKUICastContainerViewController
castContainerVC.miniMediaControlsItemEnabled = true
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = castContainerVC
window?.makeKeyAndVisible()
...
}
Dodaj tę właściwość i funkcję ustawiającą/pobierającą, aby kontrolować widoczność miniodtwarzacza (użyjemy ich w dalszej części):
var isCastControlBarsEnabled: Bool {
get {
if useCastContainerViewController {
let castContainerVC = (window?.rootViewController as? GCKUICastContainerViewController)
return castContainerVC!.miniMediaControlsItemEnabled
} else {
let rootContainerVC = (window?.rootViewController as? RootContainerViewController)
return rootContainerVC!.miniMediaControlsViewEnabled
}
}
set(notificationsEnabled) {
if useCastContainerViewController {
var castContainerVC: GCKUICastContainerViewController?
castContainerVC = (window?.rootViewController as? GCKUICastContainerViewController)
castContainerVC?.miniMediaControlsItemEnabled = notificationsEnabled
} else {
var rootContainerVC: RootContainerViewController?
rootContainerVC = (window?.rootViewController as? RootContainerViewController)
rootContainerVC?.miniMediaControlsViewEnabled = notificationsEnabled
}
}
}
Uruchom aplikację i przesyłaj film. Gdy odtwarzanie rozpocznie się na odbiorniku, w dolnej części każdej sceny powinien pojawić się miniodtwarzacz. Odtwarzaniem zdalnym możesz sterować za pomocą minikontrolera. Jeśli przełączasz się między aktywnością przeglądania a aktywnością lokalnego odtwarzacza, stan miniodtwarzacza powinien być zsynchronizowany ze stanem odtwarzania multimediów na odbiorniku.
8. Nakładka wprowadzająca
Lista kontrolna projektu Google Cast wymaga, aby aplikacja wysyłająca przedstawiła przycisk Cast dotychczasowym użytkownikom, aby poinformować ich, że aplikacja wysyłająca obsługuje teraz przesyłanie, a także pomaga użytkownikom, którzy dopiero zaczynają korzystać z Google Cast.

Klasa GCKCastContext ma metodę presentCastInstructionsViewControllerOnce, której można użyć do wyróżnienia przycisku Cast, gdy po raz pierwszy pojawi się on użytkownikom. Dodaj ten kod do plików MediaViewController.swift i MediaTableViewController.swift:
override func viewDidLoad() {
...
NotificationCenter.default.addObserver(self, selector: #selector(castDeviceDidChange),
name: NSNotification.Name.gckCastStateDidChange,
object: GCKCastContext.sharedInstance())
}
@objc func castDeviceDidChange(_: Notification) {
if GCKCastContext.sharedInstance().castState != .noDevicesAvailable {
// You can present the instructions on how to use Google Cast on
// the first time the user uses you app
GCKCastContext.sharedInstance().presentCastInstructionsViewControllerOnce(with: castButton)
}
}
Uruchom aplikację na urządzeniu mobilnym. Powinien pojawić się ekran wprowadzający.
9. Rozwinięty kontroler
Lista kontrolna projektu Google Cast wymaga, aby aplikacja wysyłająca udostępniała rozszerzony kontroler dla przesyłanych multimediów. Rozwinięty kontroler to wersja mini kontrolera na pełnym ekranie.

Rozwinięty kontroler to widok pełnoekranowy, który zapewnia pełną kontrolę nad odtwarzaniem multimediów na urządzeniu. Ten widok powinien umożliwiać aplikacji do przesyłania zarządzanie każdym aspektem sesji przesyłania, z wyjątkiem sterowania głośnością odbiornika i cyklem życia sesji (połączenie/zatrzymanie przesyłania). Zawiera też wszystkie informacje o stanie sesji multimedialnej (grafika, tytuł, podtytuł itp.).
Funkcjonalność tego widoku jest realizowana przez klasę GCKUIExpandedMediaControlsViewController.
Najpierw musisz włączyć domyślny rozszerzony kontroler w kontekście przesyłania. Zmodyfikuj AppDelegate.swift, aby włączyć domyślny rozszerzony kontroler:
import GoogleCast
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
...
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
// Add after the setShareInstanceWith(options) is set.
GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true
...
}
...
}
Dodaj ten kod do pliku MediaViewController.swift, aby wczytać rozwinięty kontroler, gdy użytkownik rozpocznie przesyłanie filmu:
@objc func playSelectedItemRemotely() {
...
appDelegate?.isCastControlBarsEnabled = false
GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()
}
Rozwinięty kontroler zostanie też automatycznie uruchomiony, gdy użytkownik kliknie minikontroler.
Uruchom aplikację i przesyłaj film. Powinien się wyświetlić rozwinięty kontroler. Wróć do listy filmów i kliknij miniodtwarzacz, aby ponownie załadować rozszerzony odtwarzacz.
10. Dodawanie obsługi Cast Connect
Biblioteka Cast Connect umożliwia istniejącym aplikacjom wysyłającym komunikację z aplikacjami na Androida TV za pomocą protokołu Cast. Cast Connect korzysta z infrastruktury Cast, a aplikacja na Androida TV działa jako odbiornik.
Zależności
W Podfile upewnij się, że google-cast-sdk jest skierowany na 4.4.8 lub wyżej, jak podano poniżej. Jeśli wprowadzisz zmiany w pliku, uruchom pod update w konsoli, aby zsynchronizować zmiany z projektem.
pod 'google-cast-sdk', '>=4.4.8'
GCKLaunchOptions
Aby uruchomić aplikację na Androida TV, zwaną też odbiornikiem Androida, musimy ustawić flagę androidReceiverCompatible na wartość true w obiekcie GCKLaunchOptions. Ten obiekt GCKLaunchOptions określa sposób uruchamiania odbiornika i jest przekazywany do obiektów GCKCastOptions, które są ustawiane we współdzielonej instancji za pomocą GCKCastContext.setSharedInstanceWith.
Dodaj do pliku AppDelegate.swift te wiersze:
let options = GCKCastOptions(discoveryCriteria:
GCKDiscoveryCriteria(applicationID: kReceiverAppID))
...
/** Following code enables CastConnect */
let launchOptions = GCKLaunchOptions()
launchOptions.androidReceiverCompatible = true
options.launchOptions = launchOptions
GCKCastContext.setSharedInstanceWith(options)
Ustawianie danych logowania do uruchamiania
Po stronie nadawcy możesz użyć symbolu GCKCredentialsData, aby określić, kto dołącza do sesji. Symbol credentials to ciąg znaków, który może być zdefiniowany przez użytkownika, o ile aplikacja na Androida TV jest w stanie go odczytać. Wartość GCKCredentialsData jest przekazywana do aplikacji na Androida TV tylko podczas uruchamiania lub dołączania. Jeśli ustawisz go ponownie, gdy jesteś połączony, nie zostanie on przekazany do aplikacji na Androida TV.
Aby ustawić dane logowania do uruchamiania, należy zdefiniować GCKCredentialsData w dowolnym momencie po ustawieniu GCKLaunchOptions. Aby to zademonstrować, dodajmy logikę przycisku Creds, która będzie ustawiać dane logowania przekazywane podczas nawiązywania sesji. Dodaj do pliku MediaTableViewController.swift ten kod:
class MediaTableViewController: UITableViewController, GCKSessionManagerListener, MediaListModelDelegate, GCKRequestDelegate {
...
private var credentials: String? = nil
...
override func viewDidLoad() {
...
navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Creds", style: .plain,
target: self, action: #selector(toggleLaunchCreds))
...
setLaunchCreds()
}
...
@objc func toggleLaunchCreds(_: Any){
if (credentials == nil) {
credentials = "{\"userId\":\"id123\"}"
} else {
credentials = nil
}
Toast.displayMessage("Launch Credentials: "+(credentials ?? "Null"), for: 3, in: appDelegate?.window)
print("Credentials set: "+(credentials ?? "Null"))
setLaunchCreds()
}
...
func setLaunchCreds() {
GCKCastContext.sharedInstance()
.setLaunch(GCKCredentialsData(credentials: credentials))
}
}
Ustawianie danych logowania w żądaniu wczytania
Aby obsługiwać credentials w aplikacjach odbiornika na Androida TV i w internecie, dodaj ten kod do klasy MediaTableViewController.swift w funkcji loadSelectedItem:
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
...
mediaLoadRequestDataBuilder.credentials = credentials
...
W zależności od aplikacji odbiorcy, do której nadawca przesyła treści, pakiet SDK automatycznie zastosuje powyższe dane logowania do trwającej sesji.
Testowanie Cast Connect
Instalowanie pliku APK Androida TV na urządzeniu Chromecast z Google TV
- Znajdź adres IP urządzenia z Androidem TV. Zwykle jest on dostępny w sekcji Ustawienia > Sieć i internet > (Nazwa sieci, z którą połączone jest urządzenie). Po prawej stronie wyświetlą się szczegóły i adres IP urządzenia w sieci.
- Użyj adresu IP urządzenia, aby połączyć się z nim za pomocą ADB w terminalu:
$ adb connect <device_ip_address>:5555
- W oknie terminala przejdź do folderu najwyższego poziomu z przykładowymi plikami do tego ćwiczenia, który został pobrany na początku. Na przykład:
$ cd Desktop/ios_codelab_src
- Zainstaluj plik APK w tym folderze na Androidzie TV, uruchamiając to polecenie:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- W menu Twoje aplikacje na urządzeniu z Androidem TV powinna być teraz widoczna aplikacja o nazwie Przesyłaj filmy.
- Po zakończeniu skompiluj i uruchom aplikację w emulatorze lub na urządzeniu mobilnym. Po nawiązaniu sesji przesyłania na urządzeniu z Androidem TV powinna się na nim uruchomić aplikacja Android Receiver. Odtwarzanie filmu z urządzenia mobilnego z iOS powinno uruchomić film na urządzeniu odbierającym z Androidem i umożliwić sterowanie odtwarzaniem za pomocą pilota do urządzenia z Androidem TV.
11. Dostosowywanie widżetów Cast
Zdarzenie inicjujące
Zacznij od folderu App-Done. Dodaj do metody applicationDidFinishLaunchingWithOptions w pliku AppDelegate.swift te informacje:
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let styler = GCKUIStyle.sharedInstance()
...
}
Po zastosowaniu co najmniej 1 dostosowania zgodnie z instrukcjami w pozostałej części tego kursu zatwierdź style, wywołując poniższy kod.
styler.apply()
Dostosowywanie widoków Cast
Możesz dostosować wszystkie widoki zarządzane przez Cast Application Framework, stosując domyślne wytyczne dotyczące stylu we wszystkich widokach. Na przykład zmieńmy kolor ikony.
styler.castViews.iconTintColor = .lightGray
W razie potrzeby możesz zastąpić ustawienia domyślne dla poszczególnych ekranów. Na przykład, aby zastąpić kolor lightGrayColor kolorem odcienia ikony tylko w przypadku rozwiniętych opcji sterowania multimediami.
styler.castViews.mediaControl.expandedController.iconTintColor = .green
Zmiana kolorów
Możesz dostosować kolor tła wszystkich widoków (lub każdego widoku z osobna). Poniższy kod ustawia kolor tła na niebieski we wszystkich widokach dostarczonych przez Cast Application Framework.
styler.castViews.backgroundColor = .blue
styler.castViews.mediaControl.miniController.backgroundColor = .yellow
Zmiana czcionek
Możesz dostosować czcionki różnych etykiet widocznych w widokach obsady. Dla celów ilustracyjnych ustawmy wszystkie czcionki na „Courier-Oblique”.
styler.castViews.headingTextFont = UIFont.init(name: "Courier-Oblique", size: 16) ?? UIFont.systemFont(ofSize: 16)
styler.castViews.mediaControl.headingTextFont = UIFont.init(name: "Courier-Oblique", size: 6) ?? UIFont.systemFont(ofSize: 6)
Zmiana domyślnych obrazów przycisków
Dodaj do projektu własne obrazy niestandardowe i przypisz je do przycisków, aby je ostylować.
let muteOnImage = UIImage.init(named: "yourImage.png")
if let muteOnImage = muteOnImage {
styler.castViews.muteOnImage = muteOnImage
}
Zmiana motywu przycisku Cast
Możesz też dostosować widżety Cast za pomocą protokołu UIAppearance. Poniższy kod stosuje motyw do GCKUICastButton we wszystkich widokach, w których się pojawia:
GCKUICastButton.appearance().tintColor = UIColor.gray
12. Gratulacje
Wiesz już, jak włączyć przesyłanie w aplikacji wideo za pomocą widżetów pakietu Cast SDK na iOS.
Więcej informacji znajdziesz w przewodniku dla programistów iOS Sender.