Panduan pengembang ini menjelaskan cara menambahkan dukungan Google Cast ke iOS Anda aplikasi pengirim menggunakan iOS Sender SDK.
Perangkat seluler atau laptop adalah pengirim yang mengontrol pemutaran, dan Perangkat Google Cast adalah penerima yang menampilkan konten di TV.
Framework pengirim mengacu pada biner library class Cast dan resource yang ada saat runtime pada pengirim. Aplikasi pengirim atau Aplikasi Cast mengacu pada aplikasi yang juga berjalan pada pengirim. Aplikasi Penerima Web mengacu pada aplikasi HTML yang berjalan di {i>Web Receiver<i}.
Framework pengirim menggunakan desain callback asinkron untuk memberi tahu pengirim aplikasi peristiwa dan transisi antara berbagai status kehidupan aplikasi Cast siklus.
Alur aplikasi
Langkah-langkah berikut menjelaskan alur eksekusi tingkat tinggi yang umum untuk pengirim. Aplikasi iOS:
- Framework Cast dimulai
GCKDiscoveryManager
berdasarkan properti yang tersedia diGCKCastOptions
ke mulai memindai perangkat. - Saat pengguna mengklik tombol Cast, framework akan menampilkan Cast dialog dengan daftar perangkat Transmisi yang ditemukan.
- Saat pengguna memilih perangkat Cast, framework akan mencoba meluncurkan Aplikasi Penerima Web di perangkat Cast.
- Kerangka kerja memanggil callback di aplikasi pengirim untuk mengonfirmasi bahwa Aplikasi Web Receiver diluncurkan.
- Kerangka kerja ini membuat saluran komunikasi antara pengirim dan Aplikasi Web Receiver.
- Framework ini menggunakan saluran komunikasi untuk memuat dan mengontrol media pemutaran di Penerima Web.
- Kerangka kerja ini menyinkronkan status pemutaran media antara pengirim dan Penerima Web: saat pengguna melakukan tindakan UI pengirim, framework akan meneruskan permintaan kontrol media tersebut ke Penerima Web, dan ketika Penerima Web mengirimkan pembaruan status media, framework memperbarui status UI pengirim.
- Saat pengguna mengklik tombol Cast untuk memutuskan sambungan dari perangkat Cast, kerangka kerja akan memutuskan sambungan aplikasi pengirim dari Penerima Web.
Untuk memecahkan masalah pengirim, Anda harus mengaktifkan logging.
Untuk daftar lengkap semua class, metode, dan peristiwa di Google Cast Framework iOS, lihat Google Cast iOS API Referensi. Bagian berikut membahas langkah-langkah untuk mengintegrasikan Cast ke aplikasi iOS.
Memanggil metode dari thread utama
Melakukan inisialisasi konteks Cast
Framework Cast memiliki objek singleton global,
GCKCastContext
, yang
mengoordinasikan semua aktivitas kerangka kerja. Objek ini harus diinisialisasi
di awal siklus hidup aplikasi, biasanya dalam
-[application:didFinishLaunchingWithOptions:]
dari delegasi aplikasi, sehingga
melanjutkan sesi otomatis pada saat aplikasi
pengirim dimulai ulang dengan benar.
GCKCastOptions
harus disediakan saat melakukan inisialisasi GCKCastContext
.
Class ini berisi opsi yang memengaruhi perilaku framework. Paling sering
pentingnya adalah ID aplikasi Penerima
Web, yang digunakan untuk memfilter
hasil penemuan dan untuk meluncurkan aplikasi Penerima Web saat sesi Cast
memulai.
Metode -[application:didFinishLaunchingWithOptions:]
juga merupakan tempat yang bagus
untuk menyiapkan delegasi logging untuk menerima pesan logging dari framework.
Ini dapat berguna untuk proses debug dan pemecahan masalah.
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, GCKLoggerDelegate { let kReceiverAppID = kGCKDefaultMediaReceiverApplicationID let kDebugLoggingEnabled = true var window: UIWindow? func applicationDidFinishLaunching(_ application: UIApplication) { let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID) let options = GCKCastOptions(discoveryCriteria: criteria) GCKCastContext.setSharedInstanceWith(options) // Enable logger. GCKLogger.sharedInstance().delegate = self ... } // MARK: - GCKLoggerDelegate func logMessage(_ message: String, at level: GCKLoggerLevel, fromFunction function: String, location: String) { if (kDebugLoggingEnabled) { print(function + " - " + message) } } }
AppDelegate.h
@interface AppDelegate () <GCKLoggerDelegate> @end
AppDelegate.m
@implementation AppDelegate static NSString *const kReceiverAppID = @"AABBCCDD"; static const BOOL kDebugLoggingEnabled = YES; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { GCKDiscoveryCriteria *criteria = [[GCKDiscoveryCriteria alloc] initWithApplicationID:kReceiverAppID]; GCKCastOptions *options = [[GCKCastOptions alloc] initWithDiscoveryCriteria:criteria]; [GCKCastContext setSharedInstanceWithOptions:options]; // Enable logger. [GCKLogger sharedInstance].delegate = self; ... return YES; } ... #pragma mark - GCKLoggerDelegate - (void)logMessage:(NSString *)message atLevel:(GCKLoggerLevel)level fromFunction:(NSString *)function location:(NSString *)location { if (kDebugLoggingEnabled) { NSLog(@"%@ - %@, %@", function, message, location); } } @end
Widget UX Cast
SDK iOS Cast menyediakan widget ini yang sesuai dengan Desain Cast {i>Checklist<i} (Daftar periksa):
Overlay Pengantar: Class
GCKCastContext
memiliki metode,presentCastInstructionsViewControllerOnceWithCastButton
, yang dapat digunakan untuk menyorot tombol Cast saat pertama kali Penerima Web yang tersedia. Aplikasi pengirim dapat menyesuaikan teks dan posisi judul teks dan tombol {i>Dismiss<i}.Tombol Cast: Mulai dari SDK pengirim iOS Cast 4.6.0, tombol transmisi selalu terlihat saat perangkat pengirim terhubung ke Wi-Fi. Saat pertama kali pengguna mengetuk di tombol Cast setelah aplikasi pertama kali dimulai, sebuah dialog izin akan muncul sehingga pengguna dapat memberi aplikasi akses jaringan lokal ke perangkat di jaringan. Selanjutnya, saat pengguna mengetuk tombol {i>cast<i}, akan muncul dialog yang mencantumkan perangkat yang ditemukan. Saat pengguna mengetuk pada tombol transmisi saat perangkat terhubung, akan menampilkan metadata media (seperti judul, nama studio rekaman, dan thumbnail gambar) atau memungkinkan pengguna memutuskan sambungan dari perangkat transmisi. Saat pengguna mengetuk tombol transmisi saat tidak ada perangkat yang tersedia, akan ditampilkan, yang memberikan informasi kepada pengguna tentang alasan perangkat tidak dapat ditemukan dan cara memecahkan masalahnya.
Pengontrol Mini: Saat pengguna mentransmisikan konten dan keluar dari konten saat ini laman konten atau pengontrol yang diperluas ke layar lain di aplikasi pengirim, pengontrol mini ditampilkan di bagian bawah layar untuk memungkinkan pengguna melihat metadata media yang sedang ditransmisikan dan untuk mengontrol pemutaran.
Pengontrol yang Diperluas: Saat pengguna mentransmisikan konten, jika mereka mengklik notifikasi media atau pengontrol mini, pengontrol yang diperluas akan diluncurkan, yang menampilkan metadata media yang sedang diputar dan menyediakan beberapa tombol untuk mengontrol pemutaran media.
Menambahkan tombol Cast
Framework ini menyediakan komponen tombol Cast sebagai subclass UIButton
. Aplikasi ini dapat
ditambahkan ke kolom judul aplikasi dengan menggabungkannya dalam UIBarButtonItem
. Karakteristik
Subclass UIViewController
dapat menginstal tombol Cast sebagai berikut:
let castButton = GCKUICastButton(frame: CGRect(x: 0, y: 0, width: 24, height: 24)) castButton.tintColor = UIColor.gray navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
GCKUICastButton *castButton = [[GCKUICastButton alloc] initWithFrame:CGRectMake(0, 0, 24, 24)]; castButton.tintColor = [UIColor grayColor]; self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:castButton];
Secara default, mengetuk tombol akan membuka dialog Cast yang disediakan oleh Google Workspace for Education.
GCKUICastButton
juga dapat ditambahkan
langsung ke {i>storyboard<i}.
Mengonfigurasi penemuan perangkat
Dalam framework, penemuan perangkat terjadi secara otomatis. Tidak perlu secara eksplisit memulai atau menghentikan proses penemuan kecuali jika Anda menerapkan UI kustom.
Penemuan dalam framework dikelola oleh kelas
GCKDiscoveryManager
,
yang merupakan properti
GCKCastContext
Tujuan
menyediakan komponen dialog Cast default untuk pemilihan perangkat dan
kontrol. Daftar perangkat diurutkan secara leksikografis berdasarkan nama yang cocok untuk perangkat.
Cara kerja pengelolaan sesi
SDK Cast memperkenalkan konsep sesi Cast, jaringan yang menggabungkan langkah-langkah untuk menghubungkan ke perangkat, meluncurkan (atau bergabung) Aplikasi penerima, menghubungkan ke aplikasi tersebut, dan menginisialisasi saluran kontrol media. Lihat Penerima Web Panduan siklus proses aplikasi untuk informasi selengkapnya tentang sesi Cast dan siklus proses Penerima Web.
Sesi dikelola oleh kelas
GCKSessionManager
,
yang merupakan properti
GCKCastContext
Sesi individual diwakili oleh subclass dari class
GCKSession
: misalnya,
GCKCastSession
mewakili sesi dengan perangkat Cast. Anda dapat mengakses Transmisi yang sedang aktif
sesi (jika ada), sebagai properti currentCastSession
dari GCKSessionManager
.
Tujuan
GCKSessionManagerListener
dapat digunakan untuk memantau peristiwa sesi, seperti pembuatan sesi,
penangguhan, pengaktifan kembali, dan penghentian. Framework akan otomatis ditangguhkan
sesi saat aplikasi pengirim beralih ke latar belakang dan mencoba melanjutkan
saat aplikasi kembali ke latar depan (atau diluncurkan kembali setelah
penghentian aplikasi yang tidak normal/tiba-tiba saat sesi aktif).
Jika dialog Cast digunakan, sesi akan dibuat dan dihapus
secara otomatis sebagai respons
terhadap {i>gesture <i}pengguna. Jika tidak, aplikasi dapat dimulai dan diakhiri
sesi secara eksplisit melalui metode pada
GCKSessionManager
Apakah aplikasi perlu melakukan pemrosesan khusus sebagai respons terhadap siklus proses sesi
peristiwa, instance dapat mendaftarkan satu atau beberapa instance GCKSessionManagerListener
dengan
GCKSessionManager
. GCKSessionManagerListener
adalah protokol yang menentukan
callback untuk peristiwa seperti awal sesi, akhir sesi, dan seterusnya.
Transfer streaming
Mempertahankan status sesi adalah dasar dari transfer streaming, dengan pengguna dapat memindahkan streaming audio dan video yang ada di seluruh perangkat menggunakan perintah suara, Google Home Aplikasi, atau layar smart. Media berhenti diputar di satu perangkat (sumber) dan berlanjut di perangkat lain ( tujuan). Setiap perangkat Cast dengan firmware terbaru dapat berfungsi sebagai sumber atau tujuan di atau transfer data.
Untuk mendapatkan perangkat tujuan baru selama transfer streaming, gunakan
GCKCastSession#device
selama
[sessionManager:didResumeCastSession:]
.
Lihat Transfer streaming di Penerima Web untuk informasi selengkapnya.
Penyambungan kembali otomatis
Framework Cast menambahkan logika koneksi ulang untuk menangani koneksi kembali secara otomatis dalam banyak kasus sudut yang halus, seperti:
- Memulihkan koneksi WiFi sementara
- Pulihkan dari mode tidur perangkat
- Memulihkan aplikasi dengan latar belakang
- Memulihkan jika aplikasi mengalami error
Cara kerja kontrol media
Jika sesi Cast dibuat dengan aplikasi Penerima Web yang mendukung media
namespace, instance
GCKRemoteMediaClient
akan dibuat secara otomatis oleh kerangka kerja; layanan ini dapat diakses
properti remoteMediaClient
dari
GCKCastSession
di instance Compute Engine.
Semua metode di GCKRemoteMediaClient
yang mengirimkan permintaan ke Penerima Web
akan mengembalikan
GCKRequest
yang
dapat digunakan untuk melacak permintaan tersebut. J
GCKRequestDelegate
dapat ditetapkan ke objek ini untuk menerima notifikasi tentang
hasil operasi.
Instance GCKRemoteMediaClient
diharapkan
mungkin digunakan bersama oleh beberapa bagian aplikasi, dan memang beberapa komponen internal
framework seperti dialog Cast dan kontrol media mini membagikan
di instance Compute Engine. Untuk itu, GCKRemoteMediaClient
mendukung pendaftaran beberapa
GCKRemoteMediaClientListener
.
Menyetel metadata media
Tujuan
GCKMediaMetadata
mewakili informasi tentang item media yang ingin ditransmisikan. Hal berikut
contoh membuat instance GCKMediaMetadata
baru untuk film dan menyetel judulnya,
sub judul, nama studio
rekaman, dan dua gambar.
let metadata = GCKMediaMetadata() metadata.setString("Big Buck Bunny (2008)", forKey: kGCKMetadataKeyTitle) metadata.setString("Big Buck Bunny tells the story of a giant rabbit with a heart bigger than " + "himself. When one sunny day three rodents rudely harass him, something " + "snaps... and the rabbit ain't no bunny anymore! In the typical cartoon " + "tradition he prepares the nasty rodents a comical revenge.", forKey: kGCKMetadataKeySubtitle) metadata.addImage(GCKImage(url: URL(string: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/images/BigBuckBunny.jpg")!, width: 480, height: 360))
GCKMediaMetadata *metadata = [[GCKMediaMetadata alloc] initWithMetadataType:GCKMediaMetadataTypeMovie]; [metadata setString:@"Big Buck Bunny (2008)" forKey:kGCKMetadataKeyTitle]; [metadata setString:@"Big Buck Bunny tells the story of a giant rabbit with a heart bigger than " "himself. When one sunny day three rodents rudely harass him, something " "snaps... and the rabbit ain't no bunny anymore! In the typical cartoon " "tradition he prepares the nasty rodents a comical revenge." forKey:kGCKMetadataKeySubtitle]; [metadata addImage:[[GCKImage alloc] initWithURL:[[NSURL alloc] initWithString:@"https://commondatastorage.googleapis.com/" "gtv-videos-bucket/sample/images/BigBuckBunny.jpg"] width:480 height:360]];
Lihat Pemilihan Gambar dan Menyimpan ke cache tentang penggunaan gambar dengan metadata media.
Muat media
Untuk memuat item media, buat
GCKMediaInformation
menggunakan metadata media. Kemudian dapatkan
GCKCastSession
dan
gunakan
GCKRemoteMediaClient
untuk memuat media di aplikasi penerima. Anda kemudian dapat menggunakan GCKRemoteMediaClient
untuk mengontrol aplikasi pemutar media yang
berjalan di penerima, seperti untuk memutar,
berhenti sejenak, dan berhenti.
let url = URL.init(string: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4") guard let mediaURL = url else { print("invalid mediaURL") return } let mediaInfoBuilder = GCKMediaInformationBuilder.init(contentURL: mediaURL) mediaInfoBuilder.streamType = GCKMediaStreamType.none; mediaInfoBuilder.contentType = "video/mp4" mediaInfoBuilder.metadata = metadata; mediaInformation = mediaInfoBuilder.build() guard let mediaInfo = mediaInformation else { print("invalid mediaInformation") return } if let request = sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInfo) { request.delegate = self }
GCKMediaInformationBuilder *mediaInfoBuilder = [[GCKMediaInformationBuilder alloc] initWithContentURL: [NSURL URLWithString:@"https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"]]; mediaInfoBuilder.streamType = GCKMediaStreamTypeNone; mediaInfoBuilder.contentType = @"video/mp4"; mediaInfoBuilder.metadata = metadata; self.mediaInformation = [mediaInfoBuilder build]; GCKRequest *request = [self.sessionManager.currentSession.remoteMediaClient loadMedia:self.mediaInformation]; if (request != nil) { request.delegate = self; }
Lihat juga bagian tentang menggunakan trek media.
Format video 4K
Untuk menentukan format video media Anda, gunakan properti videoInfo
dari
GCKMediaStatus
untuk mendapatkan instance
GCKVideoInfo
.
Instance ini berisi jenis format HDR TV serta tinggi dan lebar dalam
{i>pixel<i}. Varian format 4K ditunjukkan dalam properti hdrType
oleh enum
nilai GCKVideoInfoHDRType
.
Menambahkan pengontrol mini
Menurut Desain Cast, Checklist, aplikasi pengirim harus menyediakan kontrol persisten yang dikenal sebagai mini pengontrol yang akan muncul saat pengguna keluar dari halaman konten saat ini. Pengontrol mini menyediakan akses instan dan pengingat yang terlihat untuk sesi Cast saat ini.
Framework Cast menyediakan panel kontrol,
GCKUIMiniMediaControlsViewController
,
yang dapat ditambahkan ke scene tempat Anda ingin menampilkan pengontrol mini.
Saat aplikasi pengirim memutar live stream video atau audio, SDK otomatis menampilkan tombol putar/berhenti sebagai pengganti tombol putar/jeda di pengontrol mini.
Lihat Menyesuaikan UI Pengirim iOS untuk mengetahui cara aplikasi pengirim dapat mengonfigurasi tampilan widget Cast.
Ada dua cara untuk menambahkan pengontrol mini ke aplikasi pengirim:
- Biarkan framework Cast mengelola tata letak pengontrol mini dengan melakukan wrapping {i>view controller<i} yang sudah ada dengan pengontrol tampilannya sendiri.
- Kelola tata letak widget pengontrol mini sendiri dengan menambahkannya ke {i>view controller<i} yang ada dengan menyediakan sub-tampilan di {i>storyboard<i}.
Menggabungkan GCKUICastContainerViewController
Cara pertama adalah dengan menggunakan
GCKUICastContainerViewController
yang menggabungkan pengontrol tampilan lain dan menambahkan
GCKUIMiniMediaControlsViewController
di bagian bawah. Pendekatan ini terbatas karena Anda tidak dapat menyesuaikan
dan tidak dapat mengonfigurasi perilaku pengontrol tampilan container.
Cara pertama ini biasanya dilakukan di
Metode -[application:didFinishLaunchingWithOptions:]
untuk delegasi aplikasi:
func applicationDidFinishLaunching(_ application: UIApplication) { ... // Wrap main view in the GCKUICastContainerViewController and display the mini controller. let appStoryboard = UIStoryboard(name: "Main", bundle: nil) let navigationController = appStoryboard.instantiateViewController(withIdentifier: "MainNavigation") let castContainerVC = GCKCastContext.sharedInstance().createCastContainerController(for: navigationController) castContainerVC.miniMediaControlsItemEnabled = true window = UIWindow(frame: UIScreen.main.bounds) window!.rootViewController = castContainerVC window!.makeKeyAndVisible() ... }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... // Wrap main view in the GCKUICastContainerViewController and display the mini controller. UIStoryboard *appStoryboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; UINavigationController *navigationController = [appStoryboard instantiateViewControllerWithIdentifier:@"MainNavigation"]; GCKUICastContainerViewController *castContainerVC = [[GCKCastContext sharedInstance] createCastContainerControllerForViewController:navigationController]; castContainerVC.miniMediaControlsItemEnabled = YES; self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds]; self.window.rootViewController = castContainerVC; [self.window makeKeyAndVisible]; ... }
var castControlBarsEnabled: Bool { set(enabled) { if let castContainerVC = self.window?.rootViewController as? GCKUICastContainerViewController { castContainerVC.miniMediaControlsItemEnabled = enabled } else { print("GCKUICastContainerViewController is not correctly configured") } } get { if let castContainerVC = self.window?.rootViewController as? GCKUICastContainerViewController { return castContainerVC.miniMediaControlsItemEnabled } else { print("GCKUICastContainerViewController is not correctly configured") return false } } }
AppDelegate.h
@interface AppDelegate : UIResponder <UIApplicationDelegate> @property (nonatomic, strong) UIWindow *window; @property (nonatomic, assign) BOOL castControlBarsEnabled; @end
AppDelegate.m
@implementation AppDelegate ... - (void)setCastControlBarsEnabled:(BOOL)notificationsEnabled { GCKUICastContainerViewController *castContainerVC; castContainerVC = (GCKUICastContainerViewController *)self.window.rootViewController; castContainerVC.miniMediaControlsItemEnabled = notificationsEnabled; } - (BOOL)castControlBarsEnabled { GCKUICastContainerViewController *castContainerVC; castContainerVC = (GCKUICastContainerViewController *)self.window.rootViewController; return castContainerVC.miniMediaControlsItemEnabled; } ... @end
Menyematkan di pengontrol tampilan yang sudah ada
Cara kedua adalah menambahkan pengontrol mini langsung ke tampilan yang sudah ada
pengontrol dengan menggunakan
createMiniMediaControlsViewController
untuk membuat
GCKUIMiniMediaControlsViewController
lalu menambahkannya ke pengontrol tampilan container sebagai subtampilan.
Siapkan pengontrol tampilan di delegasi aplikasi:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { ... GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true window?.clipsToBounds = true let rootContainerVC = (window?.rootViewController as? RootContainerViewController) rootContainerVC?.miniMediaControlsViewEnabled = true ... return true }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES; self.window.clipsToBounds = YES; RootContainerViewController *rootContainerVC; rootContainerVC = (RootContainerViewController *)self.window.rootViewController; rootContainerVC.miniMediaControlsViewEnabled = YES; ... return YES; }
Di pengontrol tampilan root, buat GCKUIMiniMediaControlsViewController
dan menambahkannya ke pengontrol tampilan container sebagai subtampilan:
let kCastControlBarsAnimationDuration: TimeInterval = 0.20 @objc(RootContainerViewController) class RootContainerViewController: UIViewController, GCKUIMiniMediaControlsViewControllerDelegate { @IBOutlet weak private var _miniMediaControlsContainerView: UIView! @IBOutlet weak private var _miniMediaControlsHeightConstraint: NSLayoutConstraint! private var miniMediaControlsViewController: GCKUIMiniMediaControlsViewController! var miniMediaControlsViewEnabled = false { didSet { if self.isViewLoaded { self.updateControlBarsVisibility() } } } var overriddenNavigationController: UINavigationController? override var navigationController: UINavigationController? { get { return overriddenNavigationController } set { overriddenNavigationController = newValue } } var miniMediaControlsItemEnabled = false override func viewDidLoad() { super.viewDidLoad() let castContext = GCKCastContext.sharedInstance() self.miniMediaControlsViewController = castContext.createMiniMediaControlsViewController() self.miniMediaControlsViewController.delegate = self self.updateControlBarsVisibility() self.installViewController(self.miniMediaControlsViewController, inContainerView: self._miniMediaControlsContainerView) } func updateControlBarsVisibility() { if self.miniMediaControlsViewEnabled && self.miniMediaControlsViewController.active { self._miniMediaControlsHeightConstraint.constant = self.miniMediaControlsViewController.minHeight self.view.bringSubview(toFront: self._miniMediaControlsContainerView) } else { self._miniMediaControlsHeightConstraint.constant = 0 } UIView.animate(withDuration: kCastControlBarsAnimationDuration, animations: {() -> Void in self.view.layoutIfNeeded() }) self.view.setNeedsLayout() } func installViewController(_ viewController: UIViewController?, inContainerView containerView: UIView) { if let viewController = viewController { self.addChildViewController(viewController) viewController.view.frame = containerView.bounds containerView.addSubview(viewController.view) viewController.didMove(toParentViewController: self) } } func uninstallViewController(_ viewController: UIViewController) { viewController.willMove(toParentViewController: nil) viewController.view.removeFromSuperview() viewController.removeFromParentViewController() } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "NavigationVCEmbedSegue" { self.navigationController = (segue.destination as? UINavigationController) } } ...
RootContainerViewController.h
static const NSTimeInterval kCastControlBarsAnimationDuration = 0.20; @interface RootContainerViewController () <GCKUIMiniMediaControlsViewControllerDelegate> { __weak IBOutlet UIView *_miniMediaControlsContainerView; __weak IBOutlet NSLayoutConstraint *_miniMediaControlsHeightConstraint; GCKUIMiniMediaControlsViewController *_miniMediaControlsViewController; } @property(nonatomic, weak, readwrite) UINavigationController *navigationController; @property(nonatomic, assign, readwrite) BOOL miniMediaControlsViewEnabled; @property(nonatomic, assign, readwrite) BOOL miniMediaControlsItemEnabled; @end
RootContainerViewController.m
@implementation RootContainerViewController - (void)viewDidLoad { [super viewDidLoad]; GCKCastContext *castContext = [GCKCastContext sharedInstance]; _miniMediaControlsViewController = [castContext createMiniMediaControlsViewController]; _miniMediaControlsViewController.delegate = self; [self updateControlBarsVisibility]; [self installViewController:_miniMediaControlsViewController inContainerView:_miniMediaControlsContainerView]; } - (void)setMiniMediaControlsViewEnabled:(BOOL)miniMediaControlsViewEnabled { _miniMediaControlsViewEnabled = miniMediaControlsViewEnabled; if (self.isViewLoaded) { [self updateControlBarsVisibility]; } } - (void)updateControlBarsVisibility { if (self.miniMediaControlsViewEnabled && _miniMediaControlsViewController.active) { _miniMediaControlsHeightConstraint.constant = _miniMediaControlsViewController.minHeight; [self.view bringSubviewToFront:_miniMediaControlsContainerView]; } else { _miniMediaControlsHeightConstraint.constant = 0; } [UIView animateWithDuration:kCastControlBarsAnimationDuration animations:^{ [self.view layoutIfNeeded]; }]; [self.view setNeedsLayout]; } - (void)installViewController:(UIViewController *)viewController inContainerView:(UIView *)containerView { if (viewController) { [self addChildViewController:viewController]; viewController.view.frame = containerView.bounds; [containerView addSubview:viewController.view]; [viewController didMoveToParentViewController:self]; } } - (void)uninstallViewController:(UIViewController *)viewController { [viewController willMoveToParentViewController:nil]; [viewController.view removeFromSuperview]; [viewController removeFromParentViewController]; } - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { if ([segue.identifier isEqualToString:@"NavigationVCEmbedSegue"]) { self.navigationController = (UINavigationController *)segue.destinationViewController; } } ... @end
Tujuan
GCKUIMiniMediaControlsViewControllerDelegate
memberi tahu pengontrol tampilan host kapan pengontrol mini harus terlihat:
func miniMediaControlsViewController(_: GCKUIMiniMediaControlsViewController, shouldAppear _: Bool) { updateControlBarsVisibility() }
- (void)miniMediaControlsViewController: (GCKUIMiniMediaControlsViewController *)miniMediaControlsViewController shouldAppear:(BOOL)shouldAppear { [self updateControlBarsVisibility]; }
Tambahkan pengontrol yang diperluas
Checklist Desain Google Cast memerlukan aplikasi pengirim untuk menyediakan elemen yang diperluas pengontrol untuk media yang sedang ditransmisikan. Pengontrol yang diperluas adalah versi layar penuh dari pengontrol mini.
Pengontrol yang diperluas adalah tampilan layar penuh yang menawarkan kontrol penuh atas pemutaran media jarak jauh. Tampilan ini akan memungkinkan aplikasi transmisi mengelola setiap aspek yang dapat dikelola dari sesi transmisi, kecuali volume Penerima Web kontrol dan siklus proses sesi (menghubungkan/menghentikan transmisi). Layanan ini juga menyediakan semua informasi status tentang sesi media (karya seni, judul, subtitel, dan sebagainya maju).
Fungsi tampilan ini diimplementasikan oleh
GCKUIExpandedMediaControlsViewController
.
Hal pertama yang harus Anda lakukan adalah mengaktifkan pengontrol yang diperluas secara {i>default<i} di konteks transmisi. Ubah delegasi aplikasi untuk mengaktifkan pengontrol default yang diperluas:
func applicationDidFinishLaunching(_ application: UIApplication) { .. GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true ... }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES; .. }
Tambahkan kode berikut ke pengontrol tampilan Anda untuk memuat pengontrol yang diperluas saat pengguna mulai mentransmisikan video:
func playSelectedItemRemotely() { GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls() ... // Load your media sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInformation) }
- (void)playSelectedItemRemotely { [[GCKCastContext sharedInstance] presentDefaultExpandedMediaControls]; ... // Load your media [self.sessionManager.currentSession.remoteMediaClient loadMedia:mediaInformation]; }
Pengontrol yang diperluas juga akan diluncurkan secara otomatis saat pengguna mengetuk pengontrol mini.
Saat aplikasi pengirim memutar live stream video atau audio, SDK otomatis menampilkan tombol putar/berhenti sebagai pengganti tombol putar/jeda dalam pengontrol yang diperluas.
Lihat Menerapkan Gaya Kustom ke iOS Aplikasi untuk mengetahui cara aplikasi pengirim mengonfigurasi tampilan widget Cast.
Kontrol volume
Framework Cast akan otomatis mengelola volume untuk aplikasi pengirim. Tujuan
secara otomatis disinkronkan dengan volume Web Receiver untuk
widget UI yang disediakan. Untuk menyinkronkan penggeser yang disediakan aplikasi, gunakan
GCKUIDeviceVolumeController
Kontrol volume tombol fisik
Tombol volume fisik di perangkat pengirim dapat digunakan untuk mengubah
volume sesi Transmisi di Penerima Web menggunakan
flag physicalVolumeButtonsWillControlDeviceVolume
di
GCKCastOptions
,
yang diatur pada
GCKCastContext
.
let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID) let options = GCKCastOptions(discoveryCriteria: criteria) options.physicalVolumeButtonsWillControlDeviceVolume = true GCKCastContext.setSharedInstanceWith(options)
GCKDiscoveryCriteria *criteria = [[GCKDiscoveryCriteria alloc] initWithApplicationID:kReceiverAppID]; GCKCastOptions *options = [[GCKCastOptions alloc] initWithDiscoveryCriteria :criteria]; options.physicalVolumeButtonsWillControlDeviceVolume = YES; [GCKCastContext setSharedInstanceWithOptions:options];
Menangani error
Sangat penting bagi aplikasi pengirim untuk menangani semua callback error dan memutuskan respons terbaik untuk setiap tahap siklus proses Cast. Aplikasi dapat menampilkan dialog error kepada pengguna atau dapat memutuskan untuk mengakhiri sesi Transmisi.
Logging
GCKLogger
adalah singleton yang digunakan untuk logging oleh framework. Gunakan
GCKLoggerDelegate
untuk menyesuaikan cara
Anda menangani pesan log.
Dengan menggunakan GCKLogger
, SDK menghasilkan output logging dalam bentuk debug
pesan, error, dan peringatan. Pesan log ini membantu proses debug dan berguna
untuk memecahkan masalah
dan mengidentifikasi masalah. Secara {i>default<i}, {i>output<i} log adalah
disembunyikan, tetapi dengan menetapkan GCKLoggerDelegate
, aplikasi pengirim dapat menerima
pesan ini dari SDK dan mencatatnya ke konsol sistem.
@UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, GCKLoggerDelegate { let kReceiverAppID = kGCKDefaultMediaReceiverApplicationID let kDebugLoggingEnabled = true var window: UIWindow? func applicationDidFinishLaunching(_ application: UIApplication) { ... // Enable logger. GCKLogger.sharedInstance().delegate = self ... } // MARK: - GCKLoggerDelegate func logMessage(_ message: String, at level: GCKLoggerLevel, fromFunction function: String, location: String) { if (kDebugLoggingEnabled) { print(function + " - " + message) } } }
AppDelegate.h
@interface AppDelegate () <GCKLoggerDelegate> @end
AppDelegate.m
@implementation AppDelegate static NSString *const kReceiverAppID = @"AABBCCDD"; static const BOOL kDebugLoggingEnabled = YES; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... // Enable logger. [GCKLogger sharedInstance].delegate = self; ... return YES; } ... #pragma mark - GCKLoggerDelegate - (void)logMessage:(NSString *)message atLevel:(GCKLoggerLevel)level fromFunction:(NSString *)function location:(NSString *)location { if (kDebugLoggingEnabled) { NSLog(@"%@ - %@, %@", function, message, location); } } @end
Untuk mengaktifkan juga pesan debug dan pesan panjang, tambahkan baris ini ke kode setelah menetapkan delegasi (ditampilkan sebelumnya):
let filter = GCKLoggerFilter.init() filter.minimumLevel = GCKLoggerLevel.verbose GCKLogger.sharedInstance().filter = filter
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init]; [filter setMinimumLevel:GCKLoggerLevelVerbose]; [GCKLogger sharedInstance].filter = filter;
Anda juga dapat memfilter
pesan log yang dihasilkan oleh
GCKLogger
Tetapkan level logging minimum per class, misalnya:
let filter = GCKLoggerFilter.init() filter.setLoggingLevel(GCKLoggerLevel.verbose, forClasses: ["GCKUICastButton", "GCKUIImageCache", "NSMutableDictionary"]) GCKLogger.sharedInstance().filter = filter
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init]; [filter setLoggingLevel:GCKLoggerLevelVerbose forClasses:@[@"GCKUICastButton", @"GCKUIImageCache", @"NSMutableDictionary" ]]; [GCKLogger sharedInstance].filter = filter;
Nama class dapat berupa nama literal atau pola glob, misalnya,
GCKUI\*
dan GCK\*Session
.