1. Обзор

В этом практическом занятии вы узнаете, как модифицировать существующее iOS-приложение для воспроизведения видео, чтобы оно транслировало контент на устройство с поддержкой Google Cast .
Что такое Google Cast?
Google Cast позволяет пользователям транслировать контент с мобильного устройства на телевизор. Затем пользователи могут использовать свое мобильное устройство в качестве пульта дистанционного управления для воспроизведения мультимедиа на телевизоре.
SDK Google Cast позволяет расширить функциональность вашего приложения для управления устройствами с поддержкой Google Cast (например, телевизором или звуковой системой). SDK Cast позволяет добавлять необходимые компоненты пользовательского интерфейса в соответствии с контрольным списком дизайна Google Cast .
Контрольный список по дизайну Google Cast предназначен для того, чтобы сделать взаимодействие с Cast простым и предсказуемым на всех поддерживаемых платформах.
Что мы будем строить?
После завершения этого практического занятия у вас будет готовое iOS-приложение для воспроизведения видео, которое сможет транслировать видео на устройство Google Cast.
Что вы узнаете
- Как добавить SDK Google Cast в пример видеоприложения.
- Как добавить кнопку Cast для выбора устройства Google Cast.
- Как подключиться к устройству Cast и запустить медиаплеер.
- Как организовать кастинг видео.
- Как добавить контроллер Cast mini в ваше приложение.
- Как добавить расширенный контроллер.
- Как создать вступительный текст.
- Как настроить виджеты Cast.
- Как интегрировать Cast Connect
Что вам понадобится
- Последняя версия Xcode .
- Одно мобильное устройство с iOS 9 или более поздней версии (или симулятор Xcode).
- USB-кабель для передачи данных, чтобы подключить ваше мобильное устройство к компьютеру для разработки (если вы используете устройство).
- Устройство Google Cast, такое как Chromecast или Android TV, с подключением к интернету.
- Телевизор или монитор с HDMI-входом.
- Для тестирования интеграции Cast Connect требуется Chromecast с Google TV, но для остальных заданий Codelab он необязателен. Если у вас его нет, можете пропустить шаг добавления поддержки Cast Connect в конце этого руководства.
Опыт
- Вам потребуется иметь предыдущий опыт разработки под iOS.
- Вам также понадобятся предварительные знания о просмотре телевизора :)
Как вы будете использовать этот учебный материал?
Как бы вы оценили свой опыт разработки iOS-приложений?
Как бы вы оценили свой опыт просмотра телевизора?
2. Получите пример кода.
Вы можете либо загрузить весь пример кода на свой компьютер...
и распакуйте загруженный zip-файл.
3. Запустите демонстрационное приложение.

Для начала давайте посмотрим, как выглядит готовый пример приложения. Это простой видеоплеер. Пользователь может выбрать видео из списка, а затем воспроизвести его локально на устройстве или транслировать на устройство Google Cast.
После загрузки кода, следующие инструкции описывают, как открыть и запустить готовое демонстрационное приложение в Xcode:
Часто задаваемые вопросы
Настройка CocoaPods
Для настройки CocoaPods перейдите в консоль и установите его, используя стандартную версию Ruby, доступную в macOS:
sudo gem install cocoapods
Если у вас возникнут какие-либо проблемы, обратитесь к официальной документации , чтобы загрузить и установить менеджер зависимостей.
Настройка проекта
- Откройте терминал и перейдите в каталог codelab.
- Установите зависимости из файла Podfile.
cd app-done pod update pod install
- Откройте Xcode и выберите «Открыть другой проект...»
- Выберите файл
CastVideos-ios.xcworkspaceиз
Каталог app-doneнаходится в папке с примерами кода.
Запустите приложение
Выберите целевую платформу и симулятор, а затем запустите приложение:

Через несколько секунд должно появиться видеоприложение.
Обязательно нажмите «Разрешить», когда появится уведомление о принятии входящих сетевых подключений. Значок трансляции не будет отображаться, если эта опция не будет принята.

Нажмите кнопку «Трансляция» и выберите ваше устройство Google Cast.
Выберите видео и нажмите кнопку воспроизведения.
Видео начнет воспроизводиться на вашем устройстве Google Cast.
На экране отобразится расширенное меню управления. Для управления воспроизведением можно использовать кнопку воспроизведения/паузы.
Вернитесь к списку видеороликов.
В нижней части экрана теперь виден мини-контроллер.

Нажмите кнопку паузы на мини-контроллере, чтобы приостановить воспроизведение видео на ресивере. Нажмите кнопку воспроизведения на мини-контроллере, чтобы возобновить воспроизведение видео.
Нажмите кнопку «Трансляция», чтобы остановить трансляцию на устройство Google Cast.
4. Подготовьте стартовый проект.

Нам необходимо добавить поддержку Google Cast в загруженное вами стартовое приложение. Вот некоторые термины, связанные с Google Cast, которые мы будем использовать в этом практическом занятии:
- Приложение отправителя работает на мобильном устройстве или ноутбуке.
- Приложение- приемник работает на устройстве Google Cast.
Настройка проекта
Теперь вы готовы продолжить разработку на основе стартового проекта с помощью Xcode:
- Откройте терминал и перейдите в каталог codelab.
- Установите зависимости из файла Podfile.
cd app-start pod update pod install
- Откройте Xcode и выберите «Открыть другой проект...»
- Выберите файл
CastVideos-ios.xcworkspaceиз
Каталог app-startнаходится в папке с примерами кода.
дизайн приложения
Приложение получает список видеороликов с удаленного веб-сервера и предоставляет пользователю возможность просмотреть его. Пользователи могут выбрать видео, чтобы увидеть подробную информацию, или воспроизвести видео локально на мобильном устройстве.
Приложение состоит из двух основных контроллеров представления: MediaTableViewController и MediaViewController.
MediaTableViewController
Этот UITableViewController отображает список видео из экземпляра MediaListModel . Список видео и связанные с ними метаданные хранятся на удаленном сервере в виде JSON- файла. MediaListModel получает этот JSON и обрабатывает его для создания списка объектов MediaItem .
Объект MediaItem моделирует видео и связанные с ним метаданные, такие как заголовок, описание, URL изображения и URL потока.
MediaTableViewController создает экземпляр MediaListModel , а затем регистрируется в качестве MediaListModelDelegate чтобы получать уведомления о загрузке метаданных медиафайлов и, следовательно, о загрузке табличного представления.
Пользователю отображается список миниатюр видеороликов с кратким описанием для каждого видео. При выборе элемента соответствующий объект MediaItem передается в MediaViewController .
MediaViewController
Этот контроллер представления отображает метаданные о конкретном видео и позволяет пользователю воспроизводить видео локально на мобильном устройстве.
Контроллер представления содержит LocalPlayerView , несколько элементов управления воспроизведением и текстовое поле для отображения описания выбранного видео. Плеер занимает верхнюю часть экрана, оставляя место для подробного описания видео ниже. Пользователь может воспроизводить/приостанавливать или перематывать воспроизведение локального видео.
Часто задаваемые вопросы
5. Добавление кнопки трансляции.

Приложение с поддержкой Cast отображает кнопку Cast в каждом из своих контроллеров представления. Нажатие на кнопку Cast отображает список устройств Cast, которые пользователь может выбрать. Если пользователь воспроизводил контент локально на устройстве-отправителе, выбор устройства Cast запускает или возобновляет воспроизведение на этом устройстве Cast. В любой момент во время сеанса Cast пользователь может нажать на кнопку Cast и остановить трансляцию вашего приложения на устройство Cast. Пользователь должен иметь возможность подключаться к устройству Cast или отключаться от него, находясь на любом экране вашего приложения, как описано в контрольном списке Google Cast Design Checklist .
Конфигурация
Для запуска проекта требуются те же зависимости и настройка Xcode, что и для готового демонстрационного приложения. Вернитесь к этому разделу и выполните те же шаги, чтобы добавить GoogleCast.framework в проект запуска приложения.
Инициализация
Фреймворк Cast имеет глобальный объект-синглтон, GCKCastContext , который координирует все действия фреймворка. Этот объект необходимо инициализировать на раннем этапе жизненного цикла приложения, как правило, в методе application(_:didFinishLaunchingWithOptions:) делегата приложения, чтобы автоматическое возобновление сессии при перезапуске приложения-отправителя могло корректно запуститься, и началось сканирование устройств.
При инициализации GCKCastContext необходимо предоставить объект GCKCastOptions . Этот класс содержит параметры, влияющие на поведение фреймворка. Наиболее важным из них является идентификатор приложения-приемника, который используется для фильтрации результатов обнаружения устройств Cast и для запуска приложения-приемника при запуске сеанса Cast.
Метод application(_:didFinishLaunchingWithOptions:) также является хорошим местом для настройки делегата логирования, который будет получать сообщения логирования от фреймворка Cast. Это может быть полезно для отладки и устранения неполадок.
При разработке собственного приложения с поддержкой Cast вам необходимо зарегистрироваться в качестве разработчика Cast, а затем получить идентификатор приложения. В этом практическом занятии мы будем использовать пример идентификатора приложения.
Добавьте следующий код в файл AppDelegate.swift , чтобы инициализировать GCKCastContext с идентификатором приложения из пользовательских настроек, а также добавьте логгер для фреймворка 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)")
}
}
}
кнопка трансляции
Теперь, когда GCKCastContext инициализирован, нам нужно добавить кнопку Cast, чтобы пользователь мог выбрать устройство Cast. SDK Cast предоставляет компонент кнопки Cast под названием GCKUICastButton , являющийся подклассом UIButton . Его можно добавить в заголовок приложения, обернув его в UIBarButtonItem . Нам нужно добавить кнопку Cast как в MediaTableViewController , так и в MediaViewController .
Добавьте следующий код в MediaTableViewController.swift и 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)
...
}
...
}
Далее добавьте следующий код в файл 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)
...
}
...
}
Теперь запустите приложение. В панели навигации приложения вы увидите кнопку Cast, и при нажатии на нее отобразится список устройств Cast в вашей локальной сети. Обнаружение устройств осуществляется автоматически с помощью GCKCastContext . Выберите ваше устройство Cast, и на нем загрузится пример приложения-приемника. Вы можете переключаться между окном просмотра и окном локального проигрывателя, при этом состояние кнопки Cast будет синхронизировано.
Мы пока не добавили поддержку воспроизведения мультимедиа, поэтому вы не сможете воспроизводить видео на устройстве Cast. Нажмите кнопку Cast, чтобы остановить трансляцию.
6. Подбор видеоконтента

Мы расширим функциональность тестового приложения, чтобы оно также воспроизводило видео удаленно на устройстве Cast. Для этого нам нужно отслеживать различные события, генерируемые фреймворком Cast.
СМИ для кастинга
В общих чертах, чтобы воспроизвести медиафайл на устройстве Cast, необходимо выполнить следующие действия:
- Создайте объект
GCKMediaInformationиз Cast SDK, который моделирует медиафайл. - Пользователь подключается к устройству Cast для запуска приложения вашего ресивера.
- Загрузите объект
GCKMediaInformationв свой ресивер и воспроизведите контент. - Отслеживайте статус в СМИ.
- Отправляйте команды воспроизведения на приемник в зависимости от действий пользователя.
Шаг 1 сводится к сопоставлению одного объекта с другим; GCKMediaInformation — это то, что понимает Cast SDK, а MediaItem — это инкапсуляция медиафайла в нашем приложении; мы можем легко сопоставить MediaItem с GCKMediaInformation . Шаг 2 мы уже выполнили в предыдущем разделе. Шаг 3 легко выполнить с помощью Cast SDK.
В примере приложения MediaViewController уже реализовано различие между локальным и удаленным воспроизведением с помощью следующего перечисления:
enum PlaybackMode: Int {
case none = 0
case local
case remote
}
private var playbackMode = PlaybackMode.none
В рамках этого практического занятия вам не обязательно точно понимать всю логику работы тестового проигрывателя. Важно понимать, что медиаплеер вашего приложения необходимо будет модифицировать таким образом, чтобы он учитывал два места воспроизведения аналогичным образом.
В данный момент локальный плеер всегда находится в состоянии локального воспроизведения, поскольку он ещё ничего не знает о состояниях Casting. Нам необходимо обновлять пользовательский интерфейс на основе переходов состояний, происходящих во фреймворке Cast. Например, если мы начинаем трансляцию, нам нужно остановить локальное воспроизведение и отключить некоторые элементы управления. Аналогично, если мы останавливаем трансляцию, находясь в этом контроллере представления, нам нужно перейти к локальному воспроизведению. Для этого нам необходимо отслеживать различные события, генерируемые фреймворком Cast.
управление кастингом
В рамках платформы Cast сессия Cast объединяет этапы подключения к устройству, запуска (или присоединения) и подключения к приложению-приемнику, а также инициализации канала управления мультимедиа, если это необходимо. Канал управления мультимедиа — это способ, с помощью которого платформа Cast отправляет и получает сообщения от медиаплеера-приемника.
Сеанс Cast запускается автоматически при выборе пользователем устройства с помощью кнопки Cast и автоматически останавливается при отключении пользователя. Повторное подключение к сеансу приемника из-за проблем с сетью также автоматически обрабатывается платформой Cast.
Управление сессиями Cast осуществляется с помощью GCKSessionManager , доступ к которому можно получить через GCKCastContext.sharedInstance().sessionManager . Коллбэки GCKSessionManagerListener можно использовать для отслеживания событий сессии, таких как создание, приостановка, возобновление и завершение.
Сначала нам нужно зарегистрировать наш обработчик сессии и инициализировать несколько переменных:
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()
}
...
}
В MediaViewController нам важно получать уведомления о подключении или отключении от устройства Cast, чтобы мы могли переключаться между локальным и локальным плеером. Следует отметить, что соединение может быть нарушено не только экземпляром вашего приложения, работающим на мобильном устройстве, но и другим экземпляром вашего (или другого) приложения, работающим на другом мобильном устройстве.
Текущая активная сессия доступна по адресу GCKCastContext.sharedInstance().sessionManager.currentCastSession . Сессии создаются и закрываются автоматически в ответ на действия пользователя в диалоговых окнах Cast.
Загрузка медиафайлов
В SDK Cast объект GCKRemoteMediaClient предоставляет набор удобных API для управления удаленным воспроизведением мультимедиа на приемнике. Для GCKCastSession , поддерживающего воспроизведение мультимедиа, SDK автоматически создаст экземпляр GCKRemoteMediaClient . Доступ к нему можно получить через свойство remoteMediaClient экземпляра GCKCastSession .
Добавьте следующий код в MediaViewController.swift , чтобы загрузить выбранное в данный момент видео на приемник:
@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
}
}
}
...
}
Теперь обновите различные существующие методы, чтобы они использовали логику сессии Cast для поддержки удаленного воспроизведения:
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
}
Теперь запустите приложение на своем мобильном устройстве. Подключитесь к устройству Cast и начните воспроизведение видео. Вы должны увидеть видео на приемнике.
7. Мини-контроллер
В соответствии с контрольным списком дизайна Cast, все приложения Cast должны содержать мини-контроллер , который появляется при переходе пользователя с текущей страницы контента. Мини-контроллер обеспечивает мгновенный доступ и видимое напоминание о текущей сессии Cast.

Cast SDK предоставляет панель управления GCKUIMiniMediaControlsViewController , которую можно добавить в сцены, где вы хотите отображать постоянно отображаемые элементы управления.
Для примера приложения мы будем использовать GCKUICastContainerViewController , который оборачивает другой контроллер представления и добавляет в самом низу GCKUIMiniMediaControlsViewController .
Измените файл AppDelegate.swift и добавьте следующий код для условия if useCastContainerViewController в следующий метод:
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()
...
}
Добавьте это свойство и методы установки/получения значения для управления видимостью мини-контроллера (мы будем использовать их в последующем разделе):
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
}
}
}
Запустите приложение и начните трансляцию видео. Когда воспроизведение на приемнике начнется, в нижней части каждой сцены должен появиться мини-контроллер. Вы можете управлять воспроизведением с помощью мини-контроллера. При переключении между окном просмотра и окном локального проигрывателя состояние мини-контроллера должно оставаться синхронизированным со статусом воспроизведения мультимедиа на приемнике.
8. Вводное наложение
В соответствии с требованиями Google Cast, приложение-отправитель должно представить кнопку Cast существующим пользователям, чтобы сообщить им о поддержке функции Cast, а также помочь новым пользователям Google Cast.

Класс GCKCastContext имеет метод presentCastInstructionsViewControllerOnce , который можно использовать для подсветки кнопки Cast при ее первом показе пользователям. Добавьте следующий код в MediaViewController.swift и 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)
}
}
Запустите приложение на своем мобильном устройстве, и вы увидите вступительное сообщение.
9. Расширенный контроллер
В соответствии с требованиями Google Cast, приложение-отправитель должно предоставлять расширенный контроллер для транслируемого медиаконтента. Расширенный контроллер представляет собой полноэкранную версию мини-контроллера.

Расширенный контроллер представляет собой полноэкранный режим, обеспечивающий полный контроль над воспроизведением мультимедиа с пульта дистанционного управления. Этот режим должен позволять приложению для трансляции управлять всеми аспектами сеанса трансляции, за исключением регулировки громкости ресивера и жизненного цикла сеанса (подключение/остановка трансляции). Он также предоставляет всю информацию о состоянии сеанса мультимедиа (обложка, название, субтитры и т. д.).
Функциональность этого представления реализована классом GCKUIExpandedMediaControlsViewController .
Первое, что вам нужно сделать, это включить расширенный контроллер по умолчанию в контексте приведения типов. Измените файл AppDelegate.swift , чтобы включить расширенный контроллер по умолчанию:
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
...
}
...
}
Добавьте следующий код в файл MediaViewController.swift , чтобы загрузить развернутый контроллер, когда пользователь начнет трансляцию видео:
@objc func playSelectedItemRemotely() {
...
appDelegate?.isCastControlBarsEnabled = false
GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()
}
Расширенный контроллер также будет запускаться автоматически при нажатии пользователем на мини-контроллер.
Запустите приложение и включите воспроизведение видео. Вы должны увидеть развернутый контроллер. Вернитесь к списку видео, и при нажатии на мини-контроллер снова загрузится развернутый контроллер.
10. Добавить поддержку Cast Connect.
Библиотека Cast Connect позволяет существующим приложениям-отправителям взаимодействовать с приложениями Android TV через протокол Cast. Cast Connect строится на основе инфраструктуры Cast, при этом ваше приложение Android TV выступает в качестве приемника.
Зависимости
В вашем Podfile убедитесь, что google-cast-sdk использует версию 4.4.8 или выше, как указано ниже. Если вы внесли изменения в файл, выполните команду pod update в консоли, чтобы синхронизировать изменения с вашим проектом.
pod 'google-cast-sdk', '>=4.4.8'
GCKLaunchOptions
Для запуска приложения Android TV, также называемого Android-приемником, необходимо установить флаг androidReceiverCompatible в значение true в объекте GCKLaunchOptions . Этот объект GCKLaunchOptions определяет способ запуска приемника и передается в GCKCastOptions , которые устанавливаются в общем экземпляре с помощью GCKCastContext.setSharedInstanceWith .
Добавьте следующие строки в файл AppDelegate.swift :
let options = GCKCastOptions(discoveryCriteria:
GCKDiscoveryCriteria(applicationID: kReceiverAppID))
...
/** Following code enables CastConnect */
let launchOptions = GCKLaunchOptions()
launchOptions.androidReceiverCompatible = true
options.launchOptions = launchOptions
GCKCastContext.setSharedInstanceWith(options)
Установить учетные данные для запуска
На стороне отправителя вы можете указать GCKCredentialsData , чтобы обозначить, кто присоединяется к сессии. credentials представляют собой строку, которую может задать пользователь, если ваше приложение для Android TV может ее распознать. GCKCredentialsData передается в ваше приложение Android TV только во время запуска или присоединения. Если вы установите его снова во время подключения, он не будет передан в ваше приложение Android TV.
Для установки учетных данных запуска необходимо определить GCKCredentialsData в любое время после установки GCKLaunchOptions . Чтобы продемонстрировать это, добавим логику для кнопки «Учетные данные» , которая будет передаваться при установлении сессии. Добавьте следующий код в ваш файл MediaTableViewController.swift :
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))
}
}
Установка учетных данных для запроса на загрузку
Для обработки credentials как в веб-приложении, так и в приложении для Android TV Receiver, добавьте следующий код в класс MediaTableViewController.swift в функцию loadSelectedItem :
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
...
mediaLoadRequestDataBuilder.credentials = credentials
...
В зависимости от того, какое приложение-получатель использует отправитель для трансляции, SDK автоматически применит указанные выше учетные данные к текущей сессии.
Тестирование Cast Connect
Инструкция по установке APK-файла Android TV на Chromecast с Google TV.
- Узнайте IP-адрес вашего устройства Android TV. Обычно он находится в разделе «Настройки» > «Сеть и интернет» > (Название сети, к которой подключено ваше устройство) . Справа отобразятся подробные сведения и IP-адрес вашего устройства в этой сети.
- Используйте IP-адрес вашего устройства для подключения к нему через ADB с помощью терминала:
$ adb connect <device_ip_address>:5555
- В окне терминала перейдите в корневую папку, содержащую примеры кода, которые вы скачали в начале этого задания. Например:
$ cd Desktop/ios_codelab_src
- Установите файл .apk из этой папки на свой Android TV, выполнив следующую команду:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Теперь в меню «Ваши приложения» на вашем устройстве Android TV должно отображаться приложение под названием Cast Videos .
- После завершения сборки и запуска приложения на эмуляторе или мобильном устройстве. После установления сеанса трансляции с вашего Android TV должно запуститься приложение Android Receiver на вашем Android TV. Воспроизведение видео с вашего мобильного устройства iOS должно запуститься в Android Receiver, и вы сможете управлять воспроизведением с помощью пульта дистанционного управления вашего Android TV.
11. Настройка виджетов Cast
Инициализация
Начните с папки App-Done. Добавьте следующее в метод applicationDidFinishLaunchingWithOptions в файле AppDelegate.swift .
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let styler = GCKUIStyle.sharedInstance()
...
}
После того, как вы внесете одно или несколько изменений, как описано в остальной части этого практического задания, подтвердите стили, вызвав приведенный ниже код.
styler.apply()
Настройка отображения Cast
Вы можете настроить все представления, управляемые Cast Application Framework, задав стандартные правила оформления для всех представлений. В качестве примера изменим цвет значка.
styler.castViews.iconTintColor = .lightGray
При необходимости можно переопределить значения по умолчанию для каждого экрана отдельно. Например, чтобы переопределить значение lightGrayColor для цвета оттенка значка только для развернутого медиа-контроллера.
styler.castViews.mediaControl.expandedController.iconTintColor = .green
Изменение цветов
Вы можете настроить цвет фона для всех представлений (или индивидуально для каждого представления). Следующий код устанавливает синий цвет фона для всех представлений, предоставляемых Cast Application Framework.
styler.castViews.backgroundColor = .blue
styler.castViews.mediaControl.miniController.backgroundColor = .yellow
Изменение шрифтов
Вы можете настроить шрифты для различных надписей, отображаемых в окнах просмотра. Давайте для наглядности установим для всех шрифтов шрифт «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)
Изменение изображений кнопок по умолчанию
Добавьте в проект собственные изображения и назначьте их кнопкам для их оформления.
let muteOnImage = UIImage.init(named: "yourImage.png")
if let muteOnImage = muteOnImage {
styler.castViews.muteOnImage = muteOnImage
}
Изменение темы кнопки трансляции
Вы также можете изменять внешний вид виджетов Cast, используя протокол UIAppearance. Следующий код изменяет внешний вид кнопки GCKUICastButton на всех представлениях, где она отображается:
GCKUICastButton.appearance().tintColor = UIColor.gray
12. Поздравляем!
Теперь вы знаете, как включить функцию Cast для видеоприложения с помощью виджетов Cast SDK на iOS.
Для получения более подробной информации см. руководство разработчика iOS Sender .