Membuat aplikasi iOS kompatibel untuk Cast

1. Ringkasan

Logo Google Cast

Codelab ini akan mengajari Anda cara memodifikasi aplikasi video iOS yang ada untuk mentransmisikan konten di perangkat yang kompatibel untuk Google Cast.

Apa itu Google Cast?

Google Cast memungkinkan pengguna mentransmisikan konten dari perangkat seluler ke TV. Pengguna kemudian dapat menggunakan perangkat seluler sebagai remote control untuk pemutaran media di TV.

SDK Google Cast memungkinkan Anda memperluas aplikasi untuk mengontrol perangkat yang kompatibel dengan Google Cast (seperti TV atau sistem suara). SDK Cast memungkinkan Anda menambahkan komponen UI yang diperlukan berdasarkan Checklist Desain Google Cast.

Checklist Desain Google Cast disediakan untuk menyederhanakan pengalaman pengguna Cast dan membuatnya dapat diprediksi di semua platform yang didukung.

Apa yang akan kita buat?

Setelah menyelesaikan codelab ini, Anda akan memiliki aplikasi video iOS yang dapat Mentransmisikan video ke perangkat Google Cast.

Yang akan Anda pelajari

  • Cara menambahkan Google Cast SDK ke aplikasi video sampel.
  • Cara menambahkan tombol Cast untuk memilih perangkat Google Cast.
  • Cara menghubungkan ke perangkat Cast dan meluncurkan penerima media.
  • Cara mentransmisikan video.
  • Cara menambahkan pengontrol mini Cast ke aplikasi Anda.
  • Cara menambahkan pengontrol yang diperluas.
  • Cara menyediakan overlay perkenalan.
  • Cara menyesuaikan widget Cast.
  • Cara mengintegrasikan Cast Connect

Yang akan Anda butuhkan

  • Xcode terbaru.
  • Satu perangkat seluler dengan iOS 9 atau yang lebih baru (atau Simulator Xcode).
  • Kabel data USB untuk menghubungkan perangkat seluler ke komputer pengembangan (jika menggunakan perangkat).
  • Perangkat Google Cast seperti Chromecast atau Android TV yang dikonfigurasi dengan akses internet.
  • TV atau monitor dengan input HDMI.
  • Chromecast dengan Google TV diperlukan untuk menguji integrasi Cast Connect, tetapi bersifat opsional untuk sisa Codelab. Jika tidak memilikinya, lewati langkah Menambahkan Dukungan Cast Connect, menjelang akhir tutorial ini.

Pengalaman

  • Sebelumnya, Anda harus memiliki pengetahuan pengembangan iOS.
  • Anda juga perlu memiliki pengetahuan tentang menonton TV :)

Bagaimana Anda akan menggunakan tutorial ini?

Hanya membacanya Membacanya dan menyelesaikan latihan

Bagaimana Anda menilai pengalaman Anda membuat aplikasi iOS?

Pemula Menengah Mahir

Bagaimana Anda menilai pengalaman menonton TV Anda?

Pemula Menengah Mahir

2. Mendapatkan kode contoh

Anda bisa mendownload semua kode contoh ke komputer Anda...

dan mengekstrak file zip yang didownload.

3. Menjalankan aplikasi contoh

Logo Apple iOS

Pertama, mari kita lihat bagaimana tampilan contoh aplikasi yang sudah selesai. Aplikasi ini adalah pemutar video dasar. Pengguna dapat memilih video dari daftar dan kemudian dapat memutar video secara lokal di perangkat atau mentransmisikannya ke perangkat Google Cast.

Setelah kode didownload, petunjuk berikut menjelaskan cara membuka dan menjalankan aplikasi contoh yang telah selesai di Xcode:

Pertanyaan umum (FAQ)

Penyiapan CocoaPods

Untuk menyiapkan CocoaPods, buka konsol dan instal menggunakan Ruby default yang tersedia di macOS:

sudo gem install cocoapods

Jika Anda mengalami masalah, lihat dokumentasi resmi untuk mendownload dan menginstal pengelola dependensi.

Penyiapan project

  1. Buka terminal Anda dan buka direktori codelab.
  2. Instal dependensi dari Podfile.
cd app-done
pod update
pod install
  1. Buka Xcode dan pilih Open another project...
  2. Pilih file CastVideos-ios.xcworkspace dari direktori ikon folderapp-done di folder kode contoh.

Menjalankan aplikasi

Pilih target dan simulator, lalu jalankan aplikasi:

Toolbar simulator aplikasi XCode

Anda akan melihat aplikasi video muncul setelah beberapa detik.

Pastikan untuk mengklik 'Izinkan' saat notifikasi muncul tentang penerimaan koneksi jaringan masuk. Ikon Transmisi tidak akan muncul jika opsi ini tidak diterima.

Dialog konfirmasi yang meminta izin untuk menerima koneksi jaringan masuk

Klik tombol Cast, lalu pilih perangkat Google Cast.

Pilih video, klik tombol putar.

Video akan mulai diputar di perangkat Google Cast.

Pengontrol yang diperluas akan ditampilkan. Anda dapat menggunakan tombol putar/jeda untuk mengontrol pemutaran.

Kembali ke daftar video.

Pengontrol mini kini terlihat di bagian bawah layar.

Ilustrasi iPhone yang menjalankan aplikasi CastVideos dengan pengontrol mini di bagian bawah.

Klik tombol jeda di pengontrol mini untuk menjeda video pada penerima. Klik tombol putar di pengontrol mini untuk melanjutkan pemutaran video lagi.

Klik tombol Cast untuk menghentikan transmisi ke perangkat Google Cast.

4. Menyiapkan project awal

Ilustrasi iPhone yang menjalankan aplikasi CastVideo

Kita perlu menambahkan dukungan untuk Google Cast ke aplikasi awal yang Anda download. Berikut adalah beberapa terminologi Google Cast yang akan kita gunakan dalam codelab ini:

  • aplikasi pengirim berjalan di perangkat seluler atau laptop,
  • aplikasi penerima berjalan di perangkat Google Cast.

Penyiapan project

Sekarang Anda siap mem-build di atas project awal menggunakan Xcode:

  1. Buka terminal Anda dan buka direktori codelab.
  2. Instal dependensi dari Podfile.
cd app-start
pod update
pod install
  1. Buka Xcode dan pilih Open another project...
  2. Pilih file CastVideos-ios.xcworkspace dari direktori ikon folderapp-start di folder kode contoh.

Desain aplikasi

Aplikasi ini mengambil daftar video dari server web jarak jauh dan menyediakan daftar untuk dijelajahi pengguna. Pengguna dapat memilih video untuk melihat detailnya atau memutar video secara lokal di perangkat seluler.

Aplikasi ini terdiri dari dua pengontrol tampilan utama: MediaTableViewController dan MediaViewController.

MediaTableViewController

UITableViewController ini menampilkan daftar video dari instance MediaListModel. Daftar video dan metadata terkait dihosting di server jarak jauh sebagai file JSON. MediaListModel mengambil JSON ini dan memprosesnya untuk membuat daftar objek MediaItem.

Objek MediaItem memodelkan video dan metadatanya yang terkait, seperti judul, deskripsi, URL untuk gambar, dan URL untuk streaming.

MediaTableViewController membuat instance MediaListModel, lalu mendaftarkan dirinya sebagai MediaListModelDelegate untuk diberi tahu saat metadata media telah didownload sehingga dapat memuat tampilan tabel.

Pengguna akan diberikan daftar thumbnail video dengan deskripsi singkat untuk setiap video. Saat item dipilih, MediaItem yang sesuai akan diteruskan ke MediaViewController.

MediaViewController

Pengontrol tampilan ini menampilkan metadata tentang video tertentu dan memungkinkan pengguna memutar video secara lokal di perangkat seluler.

Pengontrol tampilan menghosting LocalPlayerView, beberapa kontrol media, dan area teks untuk menampilkan deskripsi video yang dipilih. Pemutar menutupi bagian atas layar, sehingga memberikan ruang untuk deskripsi mendetail video di bawah Pengguna dapat memutar/menjeda atau mencari pemutaran video lokal.

Pertanyaan umum (FAQ)

5. Menambahkan tombol Cast

Ilustrasi sepertiga atas iPhone yang menjalankan aplikasi CastVideo, yang menampilkan tombol Cast di pojok kanan atas

Aplikasi yang kompatibel untuk Cast menampilkan tombol Cast di setiap pengontrol tampilannya. Mengklik tombol Cast akan menampilkan daftar perangkat Cast yang dapat dipilih pengguna. Jika pengguna memutar konten secara lokal di perangkat pengirim, memilih perangkat Cast akan memulai atau melanjutkan pemutaran di perangkat Cast tersebut. Kapan saja selama sesi Cast, pengguna dapat mengklik tombol Cast dan menghentikan transmisi aplikasi ke perangkat Cast. Pengguna harus dapat menghubungkan ke atau memutuskan koneksi dari perangkat Cast saat berada di layar aplikasi Anda, seperti yang dijelaskan dalam Checklist Desain Google Cast.

Konfigurasi

Project awal memerlukan dependensi dan penyiapan Xcode yang sama seperti yang Anda lakukan untuk aplikasi contoh yang telah selesai. Kembali ke bagian tersebut dan ikuti langkah yang sama untuk menambahkan GoogleCast.framework ke project aplikasi awal.

Inisialisasi

Framework Cast memiliki objek singleton global, GCKCastContext, yang mengoordinasikan semua aktivitas framework. Objek ini harus diinisialisasi di awal siklus proses aplikasi, biasanya dalam metode application(_:didFinishLaunchingWithOptions:) delegasi aplikasi, sehingga kelanjutan sesi otomatis saat aplikasi pengirim dimulai ulang dapat dipicu dengan benar dan pemindaian untuk perangkat dapat dimulai.

Objek GCKCastOptions harus disediakan saat melakukan inisialisasi GCKCastContext. Class ini berisi opsi yang memengaruhi perilaku framework. Yang paling penting dari hal ini adalah ID aplikasi penerima, yang digunakan untuk memfilter hasil penemuan perangkat Cast dan meluncurkan aplikasi penerima saat sesi Cast dimulai.

Metode application(_:didFinishLaunchingWithOptions:) juga merupakan tempat yang baik untuk menyiapkan delegasi logging untuk menerima pesan logging dari framework Cast. Hal ini dapat berguna untuk proses debug dan pemecahan masalah.

Saat mengembangkan aplikasi yang kompatibel untuk Cast, Anda harus mendaftar sebagai developer Cast, lalu mendapatkan ID aplikasi untuk aplikasi tersebut. Untuk codelab ini, kita akan menggunakan contoh ID aplikasi.

Tambahkan kode berikut ke AppDelegate.swift untuk melakukan inisialisasi GCKCastContext dengan ID aplikasi dari setelan default pengguna, dan tambahkan logger untuk framework 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)")
    }
  }
}

Tombol Cast

Setelah GCKCastContext diinisialisasi, kita perlu menambahkan tombol Cast untuk memungkinkan pengguna memilih perangkat Cast. SDK Cast menyediakan komponen tombol Cast yang disebut GCKUICastButton sebagai subclass UIButton. Ini dapat ditambahkan ke panel judul aplikasi dengan menggabungkannya dalam UIBarButtonItem. Kita perlu menambahkan tombol Cast ke MediaTableViewController dan MediaViewController.

Tambahkan kode berikut ke MediaTableViewController.swift dan 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)

    ...
  }
  ...
}

Selanjutnya, tambahkan kode berikut ke MediaViewController.swift Anda:

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)

    ...
  }
  ...
}

Sekarang jalankan aplikasi. Anda akan melihat tombol Cast di menu navigasi aplikasi dan saat mengkliknya, tombol Cast akan mencantumkan perangkat Cast di jaringan lokal Anda. Penemuan perangkat dikelola secara otomatis oleh GCKCastContext. Pilih perangkat Cast dan contoh aplikasi penerima yang akan dimuat di perangkat Cast. Anda dapat menavigasi antara aktivitas penjelajahan dan aktivitas pemutar lokal, dan status tombol Cast akan tetap sinkron.

Kami belum menyediakan dukungan untuk pemutaran media, jadi Anda belum dapat memutar video di perangkat Cast. Klik tombol Cast untuk menghentikan transmisi.

6. Mentransmisikan konten video

Ilustrasi iPhone yang menjalankan aplikasi CastVideos, yang menunjukkan detail tentang video tertentu ('Tears of Steel'). Pemutar mini ada di bagian bawah

Kami akan memperluas contoh aplikasi untuk memutar video dari jarak jauh di perangkat Cast juga. Untuk melakukannya, kita harus memantau berbagai peristiwa yang dihasilkan oleh framework Cast.

Mentransmisikan media

Pada level tinggi, jika Anda ingin memutar media di perangkat Transmisi, hal berikut harus terjadi:

  1. Buat objek GCKMediaInformation dari SDK Cast yang memodelkan item media.
  2. Pengguna terhubung ke perangkat Cast untuk meluncurkan aplikasi penerima.
  3. Muat objek GCKMediaInformation ke penerima Anda dan putar kontennya.
  4. Lacak status media.
  5. Kirim perintah pemutaran ke penerima berdasarkan interaksi pengguna.

Langkah 1 berarti memetakan satu objek ke objek lainnya; GCKMediaInformation adalah sesuatu yang dipahami SDK Cast dan MediaItem adalah enkapsulasi aplikasi untuk item media; kita dapat dengan mudah memetakan MediaItem ke GCKMediaInformation. Kita telah menyelesaikan Langkah 2 di bagian sebelumnya. Langkah 3 mudah dilakukan dengan Cast SDK.

Aplikasi contoh MediaViewController sudah membedakan antara pemutaran lokal vs jarak jauh dengan menggunakan enum ini:

enum PlaybackMode: Int {
  case none = 0
  case local
  case remote
}

private var playbackMode = PlaybackMode.none

Dalam codelab ini Anda tidak perlu memahami keseluruhan cara kerja semua logika pemutar contoh. Tetapi Anda perlu memahami bahwa pemutar media aplikasi harus dimodifikasi agar mengetahui dua lokasi pemutaran dengan cara yang serupa.

Saat ini pemutar lokal selalu dalam status pemutaran lokal karena belum mengetahui apa pun tentang status Transmisi. Kita perlu mengupdate UI berdasarkan transisi status yang terjadi dalam framework Cast. Misalnya, jika mulai melakukan transmisi, kita perlu menghentikan pemutaran lokal dan menonaktifkan beberapa kontrol. Demikian pula, jika menghentikan transmisi saat berada di pengontrol tampilan ini, kita perlu beralih ke pemutaran lokal. Untuk menanganinya, kita perlu memantau berbagai peristiwa yang dihasilkan oleh framework Cast.

Pengelolaan sesi transmisi

Untuk framework Cast, sesi Cast menggabungkan langkah-langkah untuk menghubungkan ke perangkat, meluncurkan (atau bergabung), menghubungkan ke aplikasi penerima, dan menginisialisasi saluran kontrol media jika sesuai. Saluran kontrol media adalah cara framework Cast mengirim dan menerima pesan dari pemutar media penerima.

Sesi Transmisi akan dimulai secara otomatis saat pengguna memilih perangkat dari tombol Cast, dan akan dihentikan secara otomatis saat pengguna memutuskan sambungan. Menghubungkan kembali ke sesi penerima karena masalah jaringan juga ditangani secara otomatis oleh framework Cast.

Sesi transmisi dikelola oleh GCKSessionManager, yang dapat diakses melalui GCKCastContext.sharedInstance().sessionManager. Callback GCKSessionManagerListener dapat digunakan untuk memantau peristiwa sesi, seperti pembuatan, penangguhan, kelanjutan, dan penghentian.

Pertama, kita harus mendaftarkan pemroses sesi dan menginisialisasi beberapa variabel:

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()
  }

  ...
}

Di MediaViewController, kita ingin diberi tahu saat terhubung atau terputus dari perangkat Cast sehingga dapat beralih ke atau dari pemutar lokal. Perhatikan, konektivitas dapat terganggu bukan hanya oleh instance aplikasi Anda yang berjalan pada perangkat seluler, tetapi juga bisa terganggu oleh instance aplikasi lainnya (atau hal lainnya) yang berjalan pada perangkat seluler berbeda.

Sesi yang saat ini aktif dapat diakses sebagai GCKCastContext.sharedInstance().sessionManager.currentCastSession. Sesi dibuat dan dihapus secara otomatis sebagai respons terhadap gestur pengguna dari dialog Cast.

Memuat media

Di SDK Cast, GCKRemoteMediaClient menyediakan kumpulan API yang mudah digunakan untuk mengelola pemutaran media jarak jauh pada penerima. Untuk GCKCastSession yang mendukung pemutaran media, instance GCKRemoteMediaClient akan dibuat secara otomatis oleh SDK. Fungsi ini dapat diakses sebagai properti remoteMediaClient dari instance GCKCastSession.

Tambahkan kode berikut ke MediaViewController.swift untuk memuat video yang saat ini dipilih di penerima:

@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
      }
    }
  }
  ...
}

Sekarang perbarui berbagai metode yang ada untuk menggunakan logika Sesi Cast guna mendukung pemutaran jarak jauh:

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
}

Sekarang, jalankan aplikasi di perangkat seluler Anda. Sambungkan ke perangkat Cast dan mulai putar video. Anda akan melihat video yang diputar pada penerima.

7. Pengontrol mini

Checklist Desain Cast mengharuskan semua aplikasi Cast menyediakan pengontrol mini agar muncul saat pengguna keluar dari halaman konten saat ini. Pengontrol mini menyediakan akses instan dan pengingat yang terlihat untuk sesi Cast saat ini.

Ilustrasi bagian bawah iPhone yang menjalankan aplikasi CastVideos, yang berfokus pada pengontrol mini

SDK Cast menyediakan panel kontrol, GCKUIMiniMediaControlsViewController, yang dapat ditambahkan ke suasana tempat Anda ingin menampilkan kontrol tetap.

Untuk aplikasi contoh, kita akan menggunakan GCKUICastContainerViewController yang menggabungkan pengontrol tampilan lain dan menambahkan GCKUIMiniMediaControlsViewController di bagian bawah.

Ubah file AppDelegate.swift dan tambahkan kode berikut untuk kondisi if useCastContainerViewController dalam metode berikut:

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

Tambahkan properti ini dan penyetel/pengambil untuk mengontrol visibilitas pengontrol mini (kita akan menggunakannya di bagian selanjutnya):

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
      }
    }
  }

Jalankan aplikasi dan transmisikan video. Saat pemutaran dimulai pada penerima, Anda akan melihat pengontrol mini muncul di bagian bawah setiap adegan. Anda dapat mengontrol pemutaran jarak jauh menggunakan pengontrol mini. Jika Anda bernavigasi antara aktivitas penjelajahan dan aktivitas pemutar lokal, status pengontrol mini harus tetap sinkron dengan status pemutaran media penerima.

8. Overlay perkenalan

Checklist desain Google Cast memerlukan aplikasi pengirim untuk memperkenalkan tombol Cast kepada pengguna yang ada guna memberi tahu mereka bahwa aplikasi pengirim kini mendukung Transmisi dan juga membantu pengguna baru ke Google Cast.

Ilustrasi iPhone yang menjalankan aplikasi CastVideo dengan overlay tombol Cast, yang menyoroti tombol Cast dan menampilkan pesan 'Sentuh untuk mentransmisikan media ke TV dan Speaker'

Class GCKCastContext memiliki metode, presentCastInstructionsViewControllerOnce, yang dapat digunakan untuk menandai tombol Cast saat pertama kali ditampilkan kepada pengguna. Tambahkan kode berikut ke MediaViewController.swift dan 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)
  }
}

Jalankan aplikasi di perangkat seluler dan Anda akan melihat overlay pengantar.

9. Pengontrol yang diperluas

Checklist desain Google Cast memerlukan aplikasi pengirim untuk menyediakan pengontrol yang diperluas untuk media yang sedang ditransmisikan. Pengontrol yang diperluas adalah versi layar penuh dari pengontrol mini.

Ilustrasi iPhone yang menjalankan aplikasi CastVideos sedang memutar video dengan pengontrol yang diperluas muncul di bagian bawah

Pengontrol yang diperluas adalah tampilan layar penuh yang menawarkan kontrol penuh atas pemutaran media jarak jauh. Tampilan ini harus memungkinkan aplikasi transmisi mengelola setiap aspek yang dapat dikelola dari sesi transmisi, kecuali kontrol volume penerima dan siklus proses sesi (menghubungkan/menghentikan transmisi). Halaman ini juga menyediakan semua informasi status tentang sesi media (karya seni, judul, subtitel, dan sebagainya).

Fungsi tampilan ini diimplementasikan oleh class GCKUIExpandedMediaControlsViewController.

Hal pertama yang harus Anda lakukan adalah mengaktifkan pengontrol default yang diperluas dalam konteks transmisi. Ubah AppDelegate.swift untuk mengaktifkan pengontrol default yang diperluas:

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

Tambahkan kode berikut ke MediaViewController.swift untuk memuat pengontrol yang diperluas saat pengguna mulai mentransmisikan video:

@objc func playSelectedItemRemotely() {
  ...
  appDelegate?.isCastControlBarsEnabled = false
  GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()
}

Pengontrol yang diperluas juga akan diluncurkan secara otomatis saat pengguna mengetuk pengontrol mini.

Jalankan aplikasi dan transmisikan video. Anda akan melihat pengontrol yang diperluas. Kembali ke daftar video dan saat Anda mengklik pengontrol mini, pengontrol yang diperluas akan dimuat lagi.

10. Menambahkan dukungan Cast Connect

Library Cast Connect memungkinkan aplikasi pengirim yang ada berkomunikasi dengan aplikasi Android TV melalui protokol Cast. Cast Connect dibangun di atas infrastruktur Cast, dengan aplikasi Android TV yang bertindak sebagai penerima.

Dependensi

Di Podfile, pastikan google-cast-sdk mengarah ke 4.4.8 atau lebih tinggi seperti yang tercantum di bawah. Jika Anda membuat perubahan pada file, jalankan pod update dari konsol untuk menyinkronkan perubahan dengan project Anda.

pod 'google-cast-sdk', '>=4.4.8'

GCKLaunchOptions

Untuk meluncurkan aplikasi Android TV, yang juga disebut sebagai Penerima Android, kita perlu menyetel tanda androidReceiverCompatible ke benar (true) di objek GCKLaunchOptions. Objek GCKLaunchOptions ini menentukan cara penerima diluncurkan dan diteruskan ke GCKCastOptions yang ditetapkan dalam instance bersama menggunakan GCKCastContext.setSharedInstanceWith.

Tambahkan baris berikut ke AppDelegate.swift Anda:

let options = GCKCastOptions(discoveryCriteria:
                          GCKDiscoveryCriteria(applicationID: kReceiverAppID))
...
/** Following code enables CastConnect */
let launchOptions = GCKLaunchOptions()
launchOptions.androidReceiverCompatible = true
options.launchOptions = launchOptions

GCKCastContext.setSharedInstanceWith(options)

Menetapkan Kredensial Peluncuran

Di sisi pengirim, Anda dapat menentukan GCKCredentialsData untuk mewakili siapa yang bergabung dalam sesi. credentials adalah string yang dapat ditentukan pengguna, selama aplikasi ATV Anda dapat memahaminya. GCKCredentialsData hanya diteruskan ke aplikasi Android TV selama waktu peluncuran atau bergabung. Jika disetel lagi saat terhubung, sandi tidak akan diteruskan ke aplikasi Android TV Anda.

Agar dapat menetapkan Kredensial Peluncuran, GCKCredentialsData harus ditentukan kapan saja setelah GCKLaunchOptions ditetapkan. Untuk mendemonstrasikan ini, mari tambahkan logika untuk tombol Creds guna menetapkan kredensial yang akan diteruskan saat sesi dibuat. Tambahkan kode berikut ke MediaTableViewController.swift Anda:

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

Menetapkan Kredensial saat Permintaan Pemuatan

Untuk menangani credentials di aplikasi Penerima Web dan Android TV, tambahkan kode berikut di class MediaTableViewController.swift pada fungsi loadSelectedItem:

let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
...
mediaLoadRequestDataBuilder.credentials = credentials
...

Bergantung pada aplikasi penerima yang menjadi tujuan transmisi pengirim, SDK akan otomatis menerapkan kredensial di atas ke sesi yang sedang berlangsung.

Menguji Cast Connect

Langkah-langkah untuk menginstal APK Android TV di Chromecast dengan Google TV

  1. Temukan Alamat IP perangkat Android TV Anda. Biasanya, opsi ini tersedia di bagian Setelan > Jaringan & Internet > (Nama jaringan yang terhubung dengan perangkat Anda). Di sebelah kanan, detail dan IP perangkat Anda akan ditampilkan di jaringan.
  2. Gunakan alamat IP untuk perangkat Anda agar bisa terhubung melalui ADB menggunakan terminal:
$ adb connect <device_ip_address>:5555
  1. Dari jendela terminal, buka folder tingkat teratas untuk contoh codelab yang Anda download di awal codelab ini. Contoh:
$ cd Desktop/ios_codelab_src
  1. Instal file .apk di folder ini ke Android TV Anda dengan menjalankan:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. Sekarang Anda dapat melihat aplikasi dengan nama Cast Video di menu Aplikasi Anda di perangkat Android TV.
  2. Setelah selesai, build dan jalankan aplikasi di emulator atau perangkat seluler. Saat membuat sesi transmisi dengan perangkat Android TV, aplikasi Penerima Android di Android TV Anda seharusnya sudah diluncurkan. Dengan memutar video dari pengirim seluler iOS, video akan diluncurkan di Penerima Android dan memungkinkan Anda mengontrol pemutaran menggunakan remote untuk perangkat Android TV.

11. Menyesuaikan widget Cast

Inisialisasi

Mulai dengan folder {i>App-Done<i}. Tambahkan hal berikut ke metode applicationDidFinishLaunchingWithOptions di file AppDelegate.swift Anda.

func application(_: UIApplication,
                 didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
  ...
  let styler = GCKUIStyle.sharedInstance()
  ...
}

Setelah Anda selesai menerapkan satu atau beberapa penyesuaian seperti yang disebutkan di bagian lain codelab ini, terapkan gaya dengan memanggil kode di bawah ini

styler.apply()

Menyesuaikan tampilan Cast

Anda dapat menyesuaikan semua tampilan yang dikelola Framework Aplikasi Cast dengan memiliki panduan gaya default di seluruh tampilan. Sebagai contoh, mari kita ubah warna tint ikon.

styler.castViews.iconTintColor = .lightGray

Anda dapat mengganti default per layar jika perlu. Misalnya, untuk mengganti lightGrayColor untuk warna tint ikon hanya untuk pengontrol media yang diperluas.

styler.castViews.mediaControl.expandedController.iconTintColor = .green

Mengubah warna

Anda dapat menyesuaikan warna latar belakang untuk semua tampilan (atau tampilan individual untuk setiap tampilan). Kode berikut menyetel warna latar belakang menjadi biru untuk semua tampilan yang disediakan Framework Aplikasi Cast.

styler.castViews.backgroundColor = .blue
styler.castViews.mediaControl.miniController.backgroundColor = .yellow

Mengubah font

Anda dapat menyesuaikan font untuk berbagai label yang terlihat dalam tampilan transmisi. Mari kita setel semua font ke ‘Courier-Oblique' untuk tujuan ilustrasi.

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)

Mengubah gambar tombol default

Tambahkan gambar kustom Anda sendiri ke project, dan tetapkan gambar ke tombol Anda untuk memberi gaya.

let muteOnImage = UIImage.init(named: "yourImage.png")
if let muteOnImage = muteOnImage {
  styler.castViews.muteOnImage = muteOnImage
}

Mengubah tema tombol Cast

Anda juga dapat menerapkan tema Widget Cast menggunakan Protokol UIAppearance. Kode berikut memberi tema GCKUICastButton pada semua tampilan yang muncul:

GCKUICastButton.appearance().tintColor = UIColor.gray

12. Selamat

Kini Anda telah mengetahui cara membuat aplikasi video yang kompatibel untuk Cast menggunakan widget SDK Cast di iOS.

Untuk detail selengkapnya, lihat panduan developer Pengirim iOS.