1. Panoramica
Questo codelab ti insegnerà a modificare un'app video per iOS esistente per trasmettere contenuti su un dispositivo compatibile con Google Cast.
Che cos'è Google Cast?
Google Cast consente agli utenti di trasmettere contenuti da un dispositivo mobile a una TV. Gli utenti possono quindi utilizzare il proprio dispositivo mobile come telecomando per la riproduzione di contenuti multimediali sulla TV.
L'SDK Google Cast ti consente di estendere la tua app per controllare i dispositivi compatibili con Google Cast, ad esempio una TV o un impianto audio. L'SDK Cast ti consente di aggiungere i componenti dell'interfaccia utente necessari in base all'elenco di controllo per la progettazione di Google Cast.
L'elenco di controllo per la progettazione di Google Cast viene fornito per rendere l'esperienza utente di Google Cast semplice e prevedibile su tutte le piattaforme supportate.
Cosa realizzeremo?
Al termine di questo codelab, avrai a disposizione un'app video per iOS in grado di trasmettere video a un dispositivo Google Cast.
Obiettivi didattici
- Come aggiungere l'SDK Google Cast a un'app video di esempio.
- Come aggiungere il pulsante Trasmetti per selezionare un dispositivo Google Cast.
- Come connettersi a un dispositivo di trasmissione e avviare un ricevitore multimediale.
- Come trasmettere un video.
- Come aggiungere un controller Cast mini alla tua app.
- Come aggiungere un controller espanso.
- Come fornire un overlay introduttivo.
- Come personalizzare i widget di trasmissione.
- Come integrare Cast Connect
Che cosa ti serve
- L'ultima versione di Xcode.
- Un dispositivo mobile con iOS 9 o versioni successive (o il simulatore Xcode).
- Un cavo dati USB per collegare il dispositivo mobile al computer di sviluppo (se utilizzi un dispositivo).
- Un dispositivo Google Cast, ad esempio Chromecast o Android TV, configurato con accesso a Internet.
- Una TV o un monitor con ingresso HDMI.
- Per testare l'integrazione di Cast Connect è necessario un Chromecast con Google TV, ma è facoltativo per gli altri contenuti del codelab. Se non ne hai uno, salta il passaggio Aggiungi supporto per Cast Connect verso la fine di questo tutorial.
Esperienza
- Devi avere una conoscenza pregressa dello sviluppo iOS.
- Devi anche aver acquisito una buona conoscenza di come guardare la TV :)
Come userai questo tutorial?
Come valuteresti la tua esperienza con lo sviluppo di app per iOS?
Come valuteresti la tua esperienza con la visione della TV?
2. Recupera il codice campione
Puoi scaricare tutto il codice campione sul tuo computer...
e decomprimi il file ZIP scaricato.
3. Esegui l'app di esempio
Innanzitutto, vediamo l'aspetto dell'app di esempio completata. L'app è un video player di base. L'utente può selezionare un video da un elenco e riprodurlo in locale sul dispositivo o trasmetterlo a un dispositivo Google Cast.
Dopo aver scaricato il codice, le seguenti istruzioni descrivono come aprire ed eseguire l'app di esempio completata in Xcode:
Domande frequenti
Configurazione di CocoaPods
Per configurare CocoaPods, vai alla console ed esegui l'installazione utilizzando Ruby predefinito disponibile su macOS:
sudo gem install cocoapods
In caso di problemi, consulta la documentazione ufficiale per scaricare e installare il gestore delle dipendenze.
Configurazione del progetto
- Vai al terminale e vai alla directory del codelab.
- Installare le dipendenze dal podfile.
cd app-done pod update pod install
- Apri Xcode e seleziona Apri un altro progetto...
- Seleziona il file
CastVideos-ios.xcworkspace
dalla directoryapp-done
nella cartella del codice di esempio.
Esegui l'app
Seleziona il target e il simulatore, quindi esegui l'app:
Dovresti visualizzare l'app video dopo qualche secondo.
Assicurati di fare clic su "Consenti" quando viene visualizzata la notifica relativa all'accettazione di connessioni di rete in entrata. Se questa opzione non viene accettata, l'icona Trasmetti non viene visualizzata.
Fai clic sul pulsante Trasmetti e seleziona il tuo dispositivo Google Cast.
Seleziona un video e fai clic sul pulsante di riproduzione.
La riproduzione del video inizierà sul tuo dispositivo Google Cast.
Verrà visualizzato il controller espanso. Puoi utilizzare il pulsante di riproduzione/pausa per controllare la riproduzione.
Torna all'elenco dei video.
Ora nella parte inferiore dello schermo è visibile un mini controller.
Fai clic sul pulsante Pausa nel mini controller per mettere in pausa il video sul ricevitore. Fai clic sul pulsante di riproduzione nel mini controller per continuare a riprodurre il video.
Fai clic sul pulsante Trasmetti per interrompere la trasmissione al dispositivo Google Cast.
4. Prepara il progetto di avvio
Dobbiamo aggiungere il supporto di Google Cast all'app iniziale che hai scaricato. Ecco alcuni termini della terminologia di Google Cast che utilizzeremo in questo codelab:
- Un'app del mittente viene eseguita su un dispositivo mobile o laptop,
- Sul dispositivo Google Cast è in esecuzione un'app per ricevitore.
Configurazione del progetto
Ora puoi iniziare a creare sulla base del progetto iniziale utilizzando Xcode:
- Vai al terminale e vai alla directory del codelab.
- Installare le dipendenze dal podfile.
cd app-start pod update pod install
- Apri Xcode e seleziona Apri un altro progetto...
- Seleziona il file
CastVideos-ios.xcworkspace
dalla directoryapp-start
nella cartella del codice di esempio.
Progettazione di app
L'app recupera un elenco di video da un server web remoto e fornisce all'utente un elenco che può sfogliare. Gli utenti possono selezionare un video per visualizzarne i dettagli o riprodurlo localmente sul dispositivo mobile.
L'app è costituita da due controller di visualizzazione principali: MediaTableViewController
e MediaViewController.
MediaTableViewController
Questo UITableViewController mostra un elenco di video da un'istanza MediaListModel
. L'elenco dei video e i relativi metadati associati vengono ospitati su un server remoto sotto forma di file JSON. MediaListModel
recupera questo JSON e lo elabora per creare un elenco di oggetti MediaItem
.
Un oggetto MediaItem
modella un video e i metadati associati, ad esempio il titolo, la descrizione, l'URL di un'immagine e l'URL dello stream.
MediaTableViewController
crea un'istanza MediaListModel
, quindi si registra come MediaListModelDelegate
per ricevere una notifica quando i metadati multimediali sono stati scaricati in modo che possa caricare la visualizzazione tabella.
All'utente viene presentato un elenco di miniature dei video con una breve descrizione per ogni video. Quando viene selezionato un elemento, il valore MediaItem
corrispondente viene passato a MediaViewController
.
MediaViewController
Questo controller di visualizzazione mostra i metadati relativi a un determinato video e consente all'utente di riprodurlo localmente sul dispositivo mobile.
Il controller di visualizzazione ospita un LocalPlayerView
, alcuni controlli multimediali e un'area di testo per mostrare la descrizione del video selezionato. Il player copre la parte superiore dello schermo, lasciando spazio alla descrizione dettagliata del video sotto. L'utente può riprodurre/mettere in pausa la riproduzione o cercare la riproduzione locale del video.
Domande frequenti
5. Aggiunta del pulsante Trasmetti
Un'applicazione compatibile con Google Cast mostra il pulsante Trasmetti in ciascuno dei relativi controller di visualizzazione. Se fai clic sul pulsante Trasmetti, viene visualizzato un elenco di dispositivi di trasmissione che l'utente può selezionare. Se l'utente riprodurva i contenuti localmente sul dispositivo mittente, la selezione di un dispositivo di trasmissione avvia o riprende la riproduzione su quel dispositivo. In qualsiasi momento durante una sessione di trasmissione, l'utente può fare clic sul pulsante Trasmetti e interrompere la trasmissione della tua applicazione al dispositivo di trasmissione. L'utente deve essere in grado di connettersi o disconnettersi dal dispositivo di trasmissione mentre è in qualsiasi schermata dell'applicazione, come descritto nell'elenco di controllo per la progettazione di Google Cast.
Configurazione
Il progetto iniziale richiede le stesse dipendenze e una configurazione Xcode che hai usato per l'app di esempio completata. Torna a questa sezione e segui gli stessi passaggi per aggiungere GoogleCast.framework
al progetto di app iniziale.
Inizializzazione
Il framework Cast ha un oggetto singleton globale, GCKCastContext
, che coordina tutte le attività del framework. Questo oggetto deve essere inizializzato all'inizio del ciclo di vita dell'applicazione, in genere nel metodo application(_:didFinishLaunchingWithOptions:)
del delegato dell'app, in modo che la ripresa automatica della sessione al riavvio dell'applicazione del mittente possa essere attivata correttamente e che possa essere avviata la scansione dei dispositivi.
Durante l'inizializzazione di GCKCastContext
è necessario specificare un oggetto GCKCastOptions
. Questa classe contiene opzioni che influiscono sul comportamento del framework. Il più importante è l'ID applicazione ricevitore, che viene utilizzato per filtrare i risultati di rilevamento dei dispositivi di trasmissione e per avviare l'applicazione ricevitore all'avvio di una sessione di trasmissione.
Il metodo application(_:didFinishLaunchingWithOptions:)
è utile anche per configurare un delegato di logging per la ricezione dei messaggi di logging dal framework di trasmissione. Questi strumenti possono essere utili per il debug e la risoluzione dei problemi.
Quando sviluppi la tua app compatibile con Google Cast, devi registrarti come sviluppatore di Google Cast e poi ottenere un ID applicazione per la tua app. Per questo codelab utilizzeremo un ID app di esempio.
Aggiungi il seguente codice a AppDelegate.swift
per inizializzare GCKCastContext
con l'ID applicazione delle impostazioni predefinite dell'utente e aggiungi un logger per il framework di 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)")
}
}
}
Pulsante Trasmetti
Ora che il GCKCastContext
è stato inizializzato, dobbiamo aggiungere il pulsante Trasmetti per consentire all'utente di selezionare un dispositivo di trasmissione. L'SDK Cast fornisce un componente del pulsante Trasmetti denominato GCKUICastButton
come sottoclasse UIButton
. Può essere aggiunto alla barra del titolo dell'applicazione racchiudendolo in un UIBarButtonItem
. Dobbiamo aggiungere il pulsante Trasmetti sia a MediaTableViewController
che a MediaViewController
.
Aggiungi il seguente codice a MediaTableViewController.swift
e 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)
...
}
...
}
Quindi, aggiungi il seguente codice a 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)
...
}
...
}
Ora esegui l'app. Dovresti vedere un pulsante Trasmetti nella barra di navigazione dell'app e, facendo clic su di esso, verranno elencati i dispositivi di trasmissione sulla tua rete locale. Il rilevamento dei dispositivi è gestito automaticamente da GCKCastContext
. Seleziona il tuo dispositivo di trasmissione e l'app ricevitore di esempio verrà caricata sul dispositivo. Puoi spostarti tra l'attività di navigazione e l'attività del player locale e lo stato del pulsante Trasmetti viene mantenuto sincronizzato.
Non abbiamo aggiunto alcun supporto per la riproduzione di contenuti multimediali, quindi non puoi ancora riprodurre video sul dispositivo di trasmissione. Fai clic sul pulsante Trasmetti per interrompere la trasmissione.
6. Trasmettere contenuti video
Estenderemo l'app di esempio anche per riprodurre video da remoto su un dispositivo di trasmissione. Per farlo, dobbiamo ascoltare i vari eventi generati dal framework Cast.
Trasmissione di contenuti multimediali
A un livello generale, se vuoi riprodurre un contenuto multimediale su un dispositivo di trasmissione, è necessario che:
- Crea un oggetto
GCKMediaInformation
dall'SDK Cast che modella un elemento multimediale. - L'utente si connette al dispositivo di trasmissione per avviare l'applicazione di ricezione.
- Carica l'oggetto
GCKMediaInformation
nel ricevitore e riproduci i contenuti. - Tieni traccia dello stato dei contenuti multimediali.
- Invia i comandi di riproduzione al destinatario in base alle interazioni dell'utente.
Il passaggio 1 equivale a mappare un oggetto a un altro; GCKMediaInformation
è qualcosa che l'SDK Cast è in grado di comprendere, mentre MediaItem
è l'incapsulamento della nostra app per un elemento multimediale; possiamo facilmente mappare un MediaItem
a un GCKMediaInformation
. Abbiamo già eseguito il passaggio 2 nella sezione precedente. Il passaggio 3 è facile da eseguire con l'SDK Cast.
L'app di esempio MediaViewController
fa già una distinzione tra riproduzione locale e remota usando questa enumerazione:
enum PlaybackMode: Int {
case none = 0
case local
case remote
}
private var playbackMode = PlaybackMode.none
In questo codelab non è importante capire esattamente come funziona tutta la logica del player di esempio. È importante capire che il media player dell'app dovrà essere modificato per tenere conto delle due posizioni di riproduzione in modo simile.
Al momento il player locale è sempre nello stato di riproduzione locale, poiché non sa ancora nulla sugli stati di trasmissione. Dobbiamo aggiornare l'interfaccia utente in base alle transizioni di stato che avvengono nel framework Cast. Ad esempio, se iniziamo a trasmettere, dobbiamo interrompere la riproduzione locale e disattivare alcuni controlli. Analogamente, se interrompiamo la trasmissione quando siamo in questo controller di visualizzazione, dobbiamo passare alla riproduzione locale. Per farlo, dobbiamo ascoltare i vari eventi generati dal framework Cast.
Gestione della sessione di trasmissione
Per il framework di trasmissione, una sessione di trasmissione combina i passaggi per la connessione a un dispositivo, l'avvio (o l'unione), la connessione a un'applicazione ricevitore e l'inizializzazione di un canale di controllo dei contenuti multimediali, se opportuno. Il canale di controllo dei contenuti multimediali è il modo in cui il framework di trasmissione invia e riceve messaggi dal media player del ricevitore.
La sessione di trasmissione viene avviata automaticamente quando l'utente seleziona un dispositivo dal pulsante Trasmetti e viene interrotta automaticamente quando l'utente si disconnette. Anche la riconnessione a una sessione del ricevitore a causa di problemi di rete viene gestita automaticamente dal framework Cast.
Le sessioni di trasmissione sono gestite dalla GCKSessionManager
, a cui è possibile accedere tramite GCKCastContext.sharedInstance().sessionManager
. I callback GCKSessionManagerListener
possono essere utilizzati per monitorare gli eventi della sessione, ad esempio la creazione, la sospensione, la ripresa e la chiusura.
Per prima cosa, dobbiamo registrare il nostro listener di sessione e inizializzare alcune variabili:
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()
}
...
}
Nel mese di MediaViewController
, ci interessa ricevere informazioni quando ci colleghiamo o ci disconnettiamo dal dispositivo di trasmissione, in modo da poter passare da o verso il player locale. Tieni presente che la connettività può essere interrotta non solo dall'istanza della tua applicazione in esecuzione sul tuo dispositivo mobile, ma anche da un'altra istanza della tua o di un'altra applicazione in esecuzione su un dispositivo mobile diverso.
La sessione attualmente attiva è accessibile come GCKCastContext.sharedInstance().sessionManager.currentCastSession
. Le sessioni vengono create e eliminate automaticamente in risposta ai gesti degli utenti nelle finestre di dialogo di trasmissione.
Caricamento contenuti multimediali
Nell'SDK Cast, GCKRemoteMediaClient
fornisce una serie di pratiche API per la gestione della riproduzione remota di contenuti multimediali sul ricevitore. Per un GCKCastSession
che supporta la riproduzione di contenuti multimediali, l'SDK crea automaticamente un'istanza di GCKRemoteMediaClient
. È possibile accedervi come proprietà remoteMediaClient
dell'istanza GCKCastSession
.
Aggiungi il seguente codice a MediaViewController.swift
per caricare il video attualmente selezionato sul ricevitore:
@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
}
}
}
...
}
Ora aggiorna i vari metodi esistenti per utilizzare la logica della sessione di trasmissione per supportare la riproduzione remota:
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
}
Ora esegui l'app sul tuo dispositivo mobile. Collegati al dispositivo di trasmissione e inizia a riprodurre un video. Dovresti vedere il video riprodotto sul ricevitore.
7. Mini controller
L'elenco di controllo per la progettazione della trasmissione richiede che tutte le app di trasmissione forniscano un mini controller perché venga visualizzato quando l'utente esce dalla pagina dei contenuti corrente. Il mini controller fornisce l'accesso immediato e un promemoria visibile per la sessione di trasmissione in corso.
L'SDK Cast fornisce una barra di controlli, GCKUIMiniMediaControlsViewController
, che può essere aggiunta alle scene in cui vuoi mostrare i controlli permanenti.
Per l'app di esempio, utilizzeremo GCKUICastContainerViewController
che aggrega un altro controller di visualizzazione e aggiunge GCKUIMiniMediaControlsViewController
nella parte inferiore.
Modifica il file AppDelegate.swift
e aggiungi il seguente codice per la condizione if useCastContainerViewController
nel seguente metodo:
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()
...
}
Aggiungi questa proprietà e imposta un setter/getter per controllare la visibilità del mini controller (che utilizzeremo in una sezione successiva):
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
}
}
}
Esegui l'app e trasmetti un video. Quando viene avviata la riproduzione sul ricevitore, dovresti vedere il mini controller nella parte inferiore di ogni scena. Puoi controllare la riproduzione da remoto utilizzando il mini controller. Se passi dall'attività di navigazione a quella locale del player, lo stato del mini controller dovrebbe rimanere sincronizzato con lo stato di riproduzione dei contenuti multimediali del ricevitore.
8. Overlay introduttivo
L'elenco di controllo per la progettazione di Google Cast richiede che un'app del mittente presenti il pulsante Trasmetti agli utenti esistenti per comunicare loro che ora l'app del mittente supporta la trasmissione e aiutare anche gli utenti che non hanno mai utilizzato Google Cast.
La classe GCKCastContext
ha un metodo, presentCastInstructionsViewControllerOnce
, che può essere utilizzato per evidenziare il pulsante Trasmetti quando viene mostrato agli utenti per la prima volta. Aggiungi il seguente codice a MediaViewController.swift
e 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)
}
}
Esegui l'app sul tuo dispositivo mobile: dovresti vedere l'overlay introduttivo.
9. Controller espanso
L'elenco di controllo per la progettazione di Google Cast richiede che un'app del mittente fornisca un controller espanso per i contenuti multimediali trasmessi. Il controller espanso è una versione a schermo intero del mini controller.
Il controller espanso è a schermo intero che offre il controllo completo della riproduzione remota di contenuti multimediali. Questa visualizzazione dovrebbe consentire a un'app di trasmissione di gestire ogni aspetto gestibile di una sessione di trasmissione, ad eccezione del controllo del volume del ricevitore e del ciclo di vita della sessione (connettere/interrompere la trasmissione). Fornisce inoltre tutte le informazioni sullo stato della sessione multimediale (artwork, titolo, sottotitolo e così via).
La funzionalità di questa visualizzazione è implementata dalla classe GCKUIExpandedMediaControlsViewController
.
La prima cosa da fare è attivare il controller espanso predefinito nel contesto di trasmissione. Modifica AppDelegate.swift
per abilitare il controller espanso predefinito:
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
...
}
...
}
Aggiungi il seguente codice a MediaViewController.swift
per caricare il controller espanso quando l'utente inizia a trasmettere un video:
@objc func playSelectedItemRemotely() {
...
appDelegate?.isCastControlBarsEnabled = false
GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()
}
Il controller espanso viene inoltre avviato automaticamente quando l'utente tocca il mini controller.
Esegui l'app e trasmetti un video. Dovresti vedere il controller espanso. Torna all'elenco dei video e, quando fai clic sul mini controller, il controller espanso verrà caricato di nuovo.
10. Aggiungere l'assistenza per Cast Connect
La libreria di Cast Connect consente alle applicazioni mittente esistenti di comunicare con le applicazioni Android TV tramite il protocollo Cast. Cast Connect si basa sull'infrastruttura di Cast e la tua app Android TV funge da ricevitore.
Dipendenze
Nel tuo Podfile
, assicurati che google-cast-sdk
punti a 4.4.8
o a un livello superiore, come elencato di seguito. Se hai apportato una modifica al file, esegui pod update
dalla console per sincronizzare la modifica con il progetto.
pod 'google-cast-sdk', '>=4.4.8'
GCKLaunchOptions
Per avviare l'applicazione Android TV, nota anche come ricevitore Android, dobbiamo impostare il flag androidReceiverCompatible
su true nell'oggetto GCKLaunchOptions
. Questo oggetto GCKLaunchOptions
determina il modo in cui il ricevitore viene avviato e viene trasmesso a GCKCastOptions
, che sono impostati nell'istanza condivisa utilizzando GCKCastContext.setSharedInstanceWith
.
Aggiungi le seguenti righe a 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)
Imposta credenziali di avvio
Sul lato del mittente, puoi specificare GCKCredentialsData
per indicare chi parteciperà alla sessione. credentials
è una stringa che può essere definita dall'utente, purché l'app ATV sia in grado di comprenderla. Il GCKCredentialsData
viene trasmesso alla tua app Android TV soltanto durante la fase di lancio o di partecipazione. Se la imposti di nuovo mentre la connessione è attiva, non verrà trasmessa all'app Android TV.
Per impostare le credenziali di lancio, è necessario definire GCKCredentialsData
in qualsiasi momento dopo l'impostazione di GCKLaunchOptions
. Per dimostrare ciò, aggiungiamo la logica per il pulsante Creds per impostare le credenziali da trasmettere quando viene stabilita la sessione. Aggiungi il seguente codice a 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))
}
}
Imposta credenziali sulla richiesta di caricamento
Per gestire credentials
sia sulle tue app web sia su come ricevitore Android TV, aggiungi il seguente codice nella tua classe MediaTableViewController.swift
nella funzione loadSelectedItem
:
let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
...
mediaLoadRequestDataBuilder.credentials = credentials
...
A seconda dell'app del destinatario a cui il mittente trasmette, l'SDK applica automaticamente le credenziali sopra indicate alla sessione in corso.
Test di Cast Connect
Procedura per installare l'APK di Android TV su Chromecast con Google TV
- Trova l'indirizzo IP del tuo dispositivo Android TV. Di solito è disponibile in Impostazioni > Rete e Internet > (Nome della rete a cui è connesso il dispositivo). Sulla destra sono visualizzati i dettagli e l'IP del dispositivo sulla rete.
- Utilizza l'indirizzo IP del dispositivo per connetterti tramite ADB utilizzando il terminale:
$ adb connect <device_ip_address>:5555
- Dalla finestra del terminale, vai alla cartella di primo livello per trovare gli esempi del codelab che hai scaricato all'inizio di questo codelab. Ad esempio:
$ cd Desktop/ios_codelab_src
- Installa il file .apk in questa cartella sulla tua Android TV eseguendo:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
- Ora dovresti riuscire a vedere un'app chiamata Trasmetti video nel menu Le tue app sul dispositivo Android TV.
- Al termine, crea ed esegui l'app su un emulatore o un dispositivo mobile. Dopo aver stabilito una sessione di trasmissione con il dispositivo Android TV, dovrebbe avviare l'applicazione Android Ricevir sulla tua Android TV. La riproduzione di un video dal tuo dispositivo mobile iOS dovrebbe avviare il video nel ricevitore Android e consentirti di controllare la riproduzione utilizzando il telecomando del tuo dispositivo Android TV.
11. Personalizzare i widget di Trasmetti
Inizializzazione
Inizia con la cartella App terminata. Aggiungi quanto segue al metodo applicationDidFinishLaunchingWithOptions
nel file AppDelegate.swift
.
func application(_: UIApplication,
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
let styler = GCKUIStyle.sharedInstance()
...
}
Una volta che hai finito di applicare una o più personalizzazioni, come menzionato nel resto di questo codelab, esegui il commit degli stili chiamando il codice di seguito.
styler.apply()
Personalizzazione delle visualizzazioni di trasmissione
Puoi personalizzare tutte le visualizzazioni gestite dal framework dell'applicazione di trasmissione impostando linee guida per lo stile predefinite nelle varie visualizzazioni. Ad esempio, cambia il colore della tonalità dell'icona.
styler.castViews.iconTintColor = .lightGray
Se necessario, puoi sostituire i valori predefiniti a livello di singola schermata. Ad esempio, per eseguire l'override di lightGrayColor per il colore della tinta dell'icona solo per il controller multimediale espanso.
styler.castViews.mediaControl.expandedController.iconTintColor = .green
Colori che cambiano
Puoi personalizzare il colore dello sfondo per tutte le visualizzazioni (o singolarmente per ogni vista). Il codice che segue imposta il colore di sfondo sul blu per tutte le viste fornite dal framework delle applicazioni di trasmissione.
styler.castViews.backgroundColor = .blue
styler.castViews.mediaControl.miniController.backgroundColor = .yellow
Modifica dei caratteri
Puoi personalizzare i caratteri per etichette diverse nelle visualizzazioni di trasmissione. Impostiamo tutti i caratteri su "Courier-Oblique" a scopo illustrativo.
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)
Modifica delle immagini predefinite dei pulsanti
Aggiungi le tue immagini personalizzate al progetto e assegnale ai pulsanti per applicare uno stile.
let muteOnImage = UIImage.init(named: "yourImage.png")
if let muteOnImage = muteOnImage {
styler.castViews.muteOnImage = muteOnImage
}
Modifica del tema del pulsante Trasmetti
Puoi anche impostare come tema i widget di trasmissione utilizzando il protocollo UIAspetto. Il seguente codice pone il tema di GCKUICastButton in tutte le visualizzazioni:
GCKUICastButton.appearance().tintColor = UIColor.gray
12. Congratulazioni
Ora sai come attivare la trasmissione di un'app video utilizzando i widget dell'SDK Cast su iOS.
Per ulteriori dettagli, consulta la guida per gli sviluppatori del mittente iOS.