این راهنمای توسعهدهنده نحوه افزودن پشتیبانی Google Cast به برنامه فرستنده iOS بااستفاده از iOS Sender SDK را شرح میدهد.
دستگاه همراه یا رایانه کیفی فرستنده است که بازپخش را کنترل میکند، و دستگاه Google Cast گیرنده است که محتوا را در تلویزیون نمایش میدهد.
چارچوب فرستنده به باینری کتابخانه کلاس Cast و منابع مرتبط موجود در زمان اجرا در فرستنده اشاره دارد. برنامه فرستنده یا برنامه Cast به برنامهای اشاره دارد که در فرستنده نیز اجرا میشود. برنامه «گیرنده وب» به برنامه HTML درحال اجرا در «گیرنده وب» اشاره دارد.
چارچوب فرستنده از طراحی فراخوان ناهمگام برای اطلاعرسانی به برنامه فرستنده درباره رویدادها و انتقال بین حالتهای مختلف چرخه عمر برنامه Cast استفاده میکند.
جریان برنامه
مراحل زیر جریان اجرای سطح بالای معمول را برای برنامه iOS فرستنده شرح میدهد:
- چارچوب Cast
GCKDiscoveryManagerبراساس ویژگیهای ارائهشده درGCKCastOptionsشروع میشود تا اسکن دستگاهها را آغاز کند. - وقتی کاربر روی دکمه «پخش محتوا» کلیک میکند، چارچوب گفتگوی «پخش محتوا» را با فهرست دستگاههای «پخش محتوا» شناساییشده ارائه میدهد.
- وقتی کاربر دستگاه Cast را انتخاب میکند، چارچوب تلاش میکند برنامه «گیرنده وب» را در دستگاه Cast راهاندازی کند.
- چارچوب، فراخوانیهای برگشتی را در برنامه فرستنده فراخوانی میکند تا تأیید کند که برنامه «گیرنده وب» راهاندازی شده است.
- این چارچوب یک کانال ارتباطی بین فرستنده و برنامههای گیرنده وب ایجاد میکند.
- چارچوب از کانال ارتباطی برای بار کردن و کنترل بازپخش رسانه در «گیرنده وب» استفاده میکند.
- چارچوب، وضعیت بازپخش رسانه را بین فرستنده و «گیرنده وب» همگامسازی میکند: وقتی کاربر کنشهای میانای کاربر فرستنده را انجام میدهد، چارچوب آن درخواستهای کنترل رسانه را به «گیرنده وب» ارسال میکند و وقتی «گیرنده وب» بهروزرسانیهای وضعیت رسانه را ارسال میکند، چارچوب وضعیت میانای کاربر فرستنده را بهروز میکند.
- وقتی کاربر روی دکمه «پخش محتوا» کلیک میکند تا اتصال از دستگاه Cast را قطع کند، چارچوب اتصال برنامه فرستنده را از «گیرنده وب» قطع میکند.
برای عیبیابی فرستنده، باید ثبت گزارش را فعال کنید.
برای فهرست جامع همه کلاسها، روشها و رویدادها در چارچوب Google Cast iOS، به مرجع Google Cast iOS API مراجعه کنید. بخشهای زیر مراحل ادغام Cast در برنامه iOS شما را پوشش میدهند.
فراخوانی روشها از رشته اصلی
مقداردهی اولیه بافت Cast
چارچوب Cast دارای یک شیء تکقلو جهانی،
GCKCastContext، است که
همه فعالیتهای چارچوب را هماهنگ میکند. این شیء باید در اوایل چرخه حیات برنامه مقداردهی اولیه شود، معمولاً در روش -[application:didFinishLaunchingWithOptions:] نماینده برنامه، تا ازسرگیری خودکار جلسه هنگام بازراهاندازی برنامه فرستنده بهدرستی راهاندازی شود.
هنگام مقداردهی اولیه GCKCastContext، باید شیء GCKCastOptions ارائه شود.
این کلاس حاوی گزینههایی است که بر رفتار چارچوب تأثیر میگذارد. مهمترین آنها شناسه برنامه «گیرنده وب» است که برای فیلتر کردن نتایج کاوش و راهاندازی برنامه «گیرنده وب» هنگام شروع جلسه Cast استفاده میشود.
روش -[application:didFinishLaunchingWithOptions:] همچنین مکان خوبی برای راهاندازی نماینده ثبت گزارش برای دریافت پیامهای ثبت گزارش از چارچوب است.
این اطلاعات میتواند برای اشکالزدایی و عیبیابی مفید باشد.
@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
ابزارههای Cast UX
کیت توسعه نرمافزار Cast iOS این ابزارهها را که با «بازبینه طراحی Cast» مطابقت دارند ارائه میدهد:
همپوشانی مقدماتی: کلاس
GCKCastContextدارای روشی است،presentCastInstructionsViewControllerOnceWithCastButton، که میتواند برای برجسته کردن دکمه «ارسال محتوا» در اولین باری که «گیرنده وب» دردسترس است استفاده شود. برنامه فرستنده میتواند نوشتار، موقعیت نوشتار عنوان، و دکمه «بستن» را سفارشیسازی کند.دکمه پخش محتوا: از Cast iOS sender SDK نسخه ۴.۶.۰ به بعد، دکمه پخش محتوا همیشه نمایان است وقتی دستگاه فرستنده به Wi-Fi متصل است. اولین باری که کاربر پساز راهاندازی اولیه برنامه روی دکمه «پخش محتوا» تکضرب میزند، کادر گفتگوی اجازهها ظاهر میشود تا کاربر بتواند به برنامه اجازه دسترسی به دستگاههای موجود در شبکه محلی را بدهد. سپس، وقتی کاربر روی دکمه پخش محتوا تکضرب میزند، یک کادر گفتگوی پخش محتوا نمایش داده میشود که دستگاههای شناساییشده را فهرست میکند. وقتی کاربر روی دکمه پخش محتوا تکضرب میزند، درحالیکه دستگاه متصل است، فراداده رسانه فعلی (مانند عنوان، نام استودیو ضبط، و تصویر کوچک) نمایش داده میشود یا به کاربر اجازه میدهد اتصال را از دستگاه پخش محتوا قطع کند. وقتی کاربر روی دکمه پخش محتوا تکضرب میزند و هیچ دستگاهی دردسترس نیست، صفحهای نمایش داده میشود که اطلاعاتی درباره دلیل پیدا نشدن دستگاهها و نحوه عیبیابی به کاربر ارائه میدهد.
کنترلکننده کوچک: وقتی کاربر درحال ارسال محتوا است و از صفحه محتوای فعلی یا کنترلکننده گسترده به صفحه دیگری در برنامه فرستنده پیمایش کرده است، کنترلکننده کوچک در پایین صفحه نمایش داده میشود تا کاربر بتواند فراداده رسانه درحال ارسال را ببیند و بازپخش را کنترل کند.
کنترلکننده گسترده: وقتی کاربر درحال ارسال محتوا است، اگر روی اعلان رسانه یا کنترلکننده کوچک کلیک کند، کنترلکننده گسترده راهاندازی میشود که فراداده رسانه درحال پخش را نمایش میدهد و چند دکمه برای کنترل بازپخش رسانه ارائه میدهد.
افزودن دکمه «پخش محتوا»
چارچوب، مؤلفه دکمه «پخش محتوا» را بهعنوان زیرکلاس UIButton ارائه میدهد. میتوان آن را با قرار دادن در UIBarButtonItem به نوار عنوان برنامه اضافه کرد. یک زیرکلاس معمولی
UIViewController میتواند دکمه «پخش محتوا» را بهصورت زیر نصب کند:
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];
بهطور پیشفرض، ضربه زدن روی دکمه، کادر گفتگوی «پخش محتوا» را که توسط چارچوب ارائه شده است باز میکند.
GCKUICastButton
را میتوان مستقیماً به فیلمنامه مصور اضافه کرد.
پیکربندی کاوش دستگاه
در این چارچوب، شناسایی دستگاه بهطور خودکار انجام میشود. نیازی نیست فرایند کاوش را بهطور صریح شروع یا متوقف کنید، مگراینکه واسط کاربر سفارشی پیادهسازی کنید.
«اکتشاف» در چارچوب توسط کلاس
GCKDiscoveryManager
مدیریت میشود که یکی از ویژگیهای
GCKCastContext
است. چارچوب
یک مؤلفه گفتگوی Cast پیشفرض برای انتخاب و کنترل دستگاه ارائه میدهد. فهرست دستگاهها بهترتیب واژهنامهای براساس نام دوستانه دستگاه مرتب شده است.
نحوه عملکرد مدیریت جلسه
Cast SDK مفهوم جلسه Cast را معرفی میکند که ایجاد آن ترکیبی از مراحل اتصال به دستگاه، راهاندازی (یا پیوستن به) برنامه Web Receiver، اتصال به آن برنامه، و مقداردهی اولیه کانال کنترل رسانه است. برای اطلاعات بیشتر درباره جلسههای Cast و چرخه عمر «گیرنده وب»، راهنمای چرخه عمر برنامه «گیرنده وب» را ببینید.
جلسهها توسط کلاس
GCKSessionManager
مدیریت میشوند که ویژگیای از
GCKCastContext است.
جلسههای تکی با زیرکلاسهای کلاس
GCKSession نشان داده میشوند: برای مثال،
GCKCastSession
جلسهها را با دستگاههای Cast نشان میدهد. میتوانید به جلسه «ارسال محتوای» فعال کنونی (درصورت وجود) بهعنوان ویژگی currentCastSession از GCKSessionManager دسترسی داشته باشید.
از میانای
GCKSessionManagerListener
میتوان برای پایش رویدادهای جلسه، مثل ایجاد، تعلیق، ازسرگیری، و پایان جلسه استفاده کرد. وقتی برنامه فرستنده به پسزمینه میرود، چارچوب بهطور خودکار جلسهها را تعلیق میکند و وقتی برنامه به پیشزمینه برمیگردد (یا پساز بسته شدن غیرعادی/ ناگهانی برنامه درحالیکه جلسه فعال بوده است، دوباره راهاندازی میشود)، تلاش میکند آنها را ازسر بگیرد.
اگر از کادر گفتگوی Cast استفاده میشود، جلسهها بهطور خودکار در پاسخ به اشارههای کاربر ایجاد و بسته میشوند. درغیراینصورت، برنامه میتواند جلسهها را بهطور صریح ازطریق روشهای موجود در
GCKSessionManager شروع کند و پایان دهد.
اگر برنامه نیاز به پردازش خاصی در پاسخ به رویدادهای چرخه حیات جلسه داشته باشد، میتواند یک یا چند نمونه GCKSessionManagerListener را با GCKSessionManager ثبت کند. GCKSessionManagerListener پروتکلی است که
فراخوانیهای برگشتی را برای رویدادهایی مثل شروع جلسه، پایان جلسه، و غیره تعریف میکند.
انتقال جاریسازی
حفظ وضعیت جلسه اساس انتقال جاریسازی است که در آن کاربران میتوانند جاریسازیهای صوتی و ویدیویی موجود را بااستفاده از فرمانهای صوتی، برنامه Google Home، یا نمایشگرهای هوشمند بین دستگاهها جابهجا کنند. پخش رسانه در یک دستگاه (منبع) متوقف میشود و در دستگاه دیگری (مقصد) ادامه مییابد. هر دستگاه Cast با جدیدترین سفتافزار میتواند بهعنوان منبع یا مقصد در انتقال جاریسازی عمل کند.
برای دریافت دستگاه مقصد جدید درطول انتقال جاریسازی، از ویژگی
GCKCastSession#device
درطول فراخوانی برگشتی
[sessionManager:didResumeCastSession:]
استفاده کنید.
برای اطلاعات بیشتر، انتقال جاریسازی در «گیرنده وب» را ببینید.
اتصال مجدد خودکار
چارچوب Cast منطق اتصال مجدد را برای مدیریت خودکار اتصال مجدد در بسیاریاز موارد خاص و ظریف اضافه میکند، مانند:
- بازیابی از قطع موقت Wi-Fi
- بازیابی از حالت خواب دستگاه
- بازیابی از پسزمینه کردن برنامه
- بازیابی درصورت ازکار افتادن برنامه
نحوه عملکرد کنترل رسانه
If a Cast session is established with a Web Receiver app that supports the media
namespace, an instance of
GCKRemoteMediaClient
will be created automatically by the framework; it can be accessed as the
remoteMediaClient property of the
GCKCastSession
instance.
همه روشهای GCKRemoteMediaClient که درخواستها را به «گیرنده وب» ارسال میکنند،
یک شیء
GCKRequest برمیگردانند که
میتوان از آن برای ردیابی آن درخواست استفاده کرد. میتوان
GCKRequestDelegate
را به این شیء اختصاص داد تا اعلانهای مربوط به نتیجه نهایی عملیات را دریافت کند.
انتظار میرود که نمونه GCKRemoteMediaClient
ممکن است توسط چندین بخش از برنامه همرسانی شود، و درواقع برخیاز مؤلفههای داخلی
چارچوب مانند کادر گفتگوی Cast و کنترلهای رسانه کوچک نمونه را همرسانی میکنند. به همین منظور، GCKRemoteMediaClient
از ثبت چند
GCKRemoteMediaClientListener پشتیبانی میکند.
تنظیم فرادادههای رسانه
کلاس
GCKMediaMetadata
اطلاعات مربوط به فایل رسانهای را که میخواهید ارسال کنید نشان میدهد. مثال زیر نمونه GCKMediaMetadata جدیدی از فیلم ایجاد میکند و عنوان، زیرعنوان، نام استودیوی ضبط، و دو تصویر را تنظیم میکند.
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]];
برای استفاده از تصاویر با فراداده رسانه، بخش انتخاب تصویر و ذخیره در حافظه نهان را ببینید.
بار کردن رسانه
برای بار کردن فایل رسانهای، بااستفاده از فراداده رسانه،
GCKMediaInformation
نمونه ایجاد کنید. سپس
GCKCastSession فعلی را دریافت کنید و
از
GCKRemoteMediaClient آن
برای بار کردن رسانه در برنامه گیرنده استفاده کنید. سپس میتوانید از GCKRemoteMediaClient
برای کنترل برنامه پخشکننده رسانه درحال اجرا در گیرنده استفاده کنید، مثلاً برای پخش،
مکث، و توقف.
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; }
همچنین بخش مربوط به استفاده از قطعههای رسانهای را ببینید.
قالب ویدیو 4K
برای تعیین قالب ویدیویی رسانهتان، از ویژگی videoInfo
GCKMediaStatus
استفاده کنید تا نمونه فعلی
GCKVideoInfo را دریافت کنید.
این نمونه شامل نوع قالب تلویزیون HDR و ارتفاع و عرض به پیکسل است. انواع قالب 4K در ویژگی hdrType با مقادیر enum GCKVideoInfoHDRType نشان داده میشوند.
افزودن کنترلکنندههای کوچک
طبق فهرست بازبینی طراحی Cast، برنامه فرستنده باید کنترل پایداری را ارائه دهد که به آن کنترلکننده کوچک میگویند و باید زمانی ظاهر شود که کاربر از صفحه محتوای فعلی خارج میشود. کنترلکننده کوچک دسترسی فوری و یادآوری قابلمشاهدهای برای جلسه «ارسال محتوای» فعلی ارائه میدهد.
چارچوب Cast نوار کنترلی ارائه میدهد،
GCKUIMiniMediaControlsViewController،
که میتوان آن را به صحنههایی که میخواهید کنترلکننده کوچک را نشان دهید اضافه کرد.
وقتی برنامه فرستنده شما درحال پخش جاریسازی زنده ویدیو یا صدا است، SDK بهطور خودکار دکمه پخش/توقف را بهجای دکمه پخش/مکث در کنترلکننده کوچک نمایش میدهد.
برای اطلاع از نحوه پیکربندی ظاهر ابزارههای Cast توسط برنامه فرستنده، به سفارشیسازی کردن میانای کاربر فرستنده iOS مراجعه کنید.
دو روش برای افزودن کنترلکننده کوچک به برنامه فرستنده وجود دارد:
- با پیچیدن کنترلکننده نمای موجودتان با کنترلکننده نمای خودش، به چارچوب Cast اجازه دهید چیدمان کنترلکننده کوچک را مدیریت کند.
- با افزودن ابزاره کنترلکننده کوچک به کنترلکننده نمای موجودتان ازطریق ارائه نمای فرعی در استوریبرد، چیدمان آن را خودتان مدیریت کنید.
Wrap using the GCKUICastContainerViewController
روش اول استفاده از
GCKUICastContainerViewController
است که کنترلکننده نمای دیگری را میپوشاند و
GCKUIMiniMediaControlsViewController
را در پایین اضافه میکند. این رویکرد از این جهت محدود است که نمیتوانید پویانمایی را سفارشیسازی کنید و نمیتوانید رفتار کنترلکننده نمای محفظه را پیکربندی کنید.
این روش اول معمولاً در
متد -[application:didFinishLaunchingWithOptions:] نماینده برنامه انجام میشود:
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
جاسازی در کنترلکننده نمای موجود
روش دوم این است که بااستفاده از
createMiniMediaControlsViewController
برای ایجاد نمونه
GCKUIMiniMediaControlsViewController
، کنترلکننده کوچک را مستقیماً به کنترلکننده نمای موجود اضافه کنید و سپس آن را بهعنوان نمای فرعی به کنترلکننده نمای محفظه اضافه کنید.
کنترلکننده نمای خود را در نماینده برنامه راهاندازی کنید:
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; }
در کنترلکننده نمای ریشه، یک نمونه GCKUIMiniMediaControlsViewController ایجاد کنید و آن را بهعنوان زیرنما به کنترلکننده نمای محفظه اضافه کنید:
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
GCKUIMiniMediaControlsViewControllerDelegate
به کنترلکننده نمای میزبان میگوید که کنترلکننده کوچک چه زمانی باید نمایان باشد:
func miniMediaControlsViewController(_: GCKUIMiniMediaControlsViewController, shouldAppear _: Bool) { updateControlBarsVisibility() }
- (void)miniMediaControlsViewController: (GCKUIMiniMediaControlsViewController *)miniMediaControlsViewController shouldAppear:(BOOL)shouldAppear { [self updateControlBarsVisibility]; }
افزودن کنترلکننده ازهم بازشده
«بازبینه طراحی Google Cast» از برنامه فرستنده میخواهد که برای رسانه درحال ارسال محتوا، کنترلکننده گسترده ارائه دهد. کنترلکننده گستردهشده نسخه تمامصفحه کنترلکننده کوچک است.
کنترلکننده گسترده نمای تمامصفحهای است که کنترل کامل بازپخش رسانه ازراهدور را ارائه میدهد. این نما باید به برنامه ارسال محتوا اجازه دهد تا همه جنبههای قابلمدیریت جلسه ارسال محتوا را مدیریت کند، بهاستثنای کنترل میزان صدای «گیرنده وب» و چرخه حیات جلسه (اتصال/ توقف ارسال محتوا). همچنین همه اطلاعات وضعیت مربوط به جلسه رسانه (کار هنری، عنوان، زیرنویس، و غیره) را ارائه میدهد.
عملکرد این نما توسط کلاس
GCKUIExpandedMediaControlsViewController
پیادهسازی میشود.
اولین کاری که باید انجام دهید این است که کنترلکننده گسترده پیشفرض را در زمینه ارسال محتوا فعال کنید. نماینده برنامه را برای فعال کردن کنترلکننده گسترده پیشفرض اصلاح کنید:
func applicationDidFinishLaunching(_ application: UIApplication) { .. GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true ... }
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES; .. }
کد زیر را به کنترلکننده نمای خود اضافه کنید تا کنترلکننده گسترشیافته را بارگیری کند وقتی کاربر شروع به پخش محتوای ویدیویی میکند:
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]; }
وقتی کاربر روی کنترلکننده کوچک تکضرب میزند، کنترلکننده گسترده نیز بهطور خودکار راهاندازی میشود.
وقتی برنامه فرستنده شما درحال پخش جاریسازی زنده ویدیو یا صدا است، SDK بهطور خودکار دکمه پخش/توقف را بهجای دکمه پخش/مکث در کنترلکننده گسترده نمایش میدهد.
برای اطلاع از نحوه پیکربندی ظاهر ابزارههای Cast توسط برنامه فرستنده، به اعمال سبکهای سفارشی در برنامه iOS مراجعه کنید.
کنترل میزان صدا
چارچوب Cast بهطور خودکار میزان صدا را برای برنامه فرستنده مدیریت میکند. چارچوب بهطور خودکار با میزان صدای «گیرنده وب» برای ابزارههای میانای کاربر ارائهشده
همگامسازی میشود. برای همگامسازی لغزنده ارائهشده توسط برنامه، از
GCKUIDeviceVolumeController استفاده کنید.
کنترل میزان صدا با دکمه فیزیکی
The physical volume buttons on the sender device can be used to change the
volume of the Cast session on the Web Receiver using the
physicalVolumeButtonsWillControlDeviceVolume flag on the
GCKCastOptions,
which is set on the
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];
مدیریت کردن خطاها
بسیار مهم است که برنامههای فرستنده همه فراخوانیهای برگشتی خطا را مدیریت کنند و بهترین پاسخ را برای هر مرحله از چرخه عمر Cast تعیین کنند. برنامه میتواند کادرهای گفتگوی خطا را به کاربر نشان دهد یا تصمیم بگیرد جلسه Cast را پایان دهد.
توجه داشته باشید که برخیاز خطاها، ازجمله
GCKErrorCode
GCKErrorCodeCancelled، رفتار موردانتظار هستند.
برای اتصالی که با GCKErrorCodeCancelled ناموفق بوده است، دوباره تلاش نکنید.
انجام این کار ممکن است منجر به رفتار غیرمنتظره شود.
ثبت
GCKLogger
یک سینگلتون است که توسط چارچوب برای ثبت گزارش استفاده میشود. از
GCKLoggerDelegate
برای سفارشیسازی نحوه مدیریت پیامهای گزارش استفاده کنید.
بااستفاده از GCKLogger، کیت توسعه نرمافزار برونداد ثبتشده را بهصورت پیامهای اشکالزدایی، خطا، و هشدار تولید میکند. این پیامهای گزارش به اشکالزدایی کمک میکنند و برای عیبیابی و شناسایی مشکلات مفید هستند. بهطور پیشفرض، خروجی گزارش
سرکوب میشود، اما با اختصاص دادن GCKLoggerDelegate، برنامه فرستنده میتواند
این پیامها را از کیت توسعه نرمافزار دریافت کند و آنها را در کنسول سیستم ثبت کند.
@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
برای فعال کردن پیامهای اشکالزدایی و پرجزئیات، این خط را پساز تنظیم نماینده (که قبلاً نشان داده شد) به کد اضافه کنید:
let filter = GCKLoggerFilter.init() filter.minimumLevel = GCKLoggerLevel.verbose GCKLogger.sharedInstance().filter = filter
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init]; [filter setMinimumLevel:GCKLoggerLevelVerbose]; [GCKLogger sharedInstance].filter = filter;
همچنین میتوانید پیامهای گزارش تولیدشده توسط
GCKLogger را فیلتر کنید.
حداقل سطح گزارشگیری را برای هر کلاس تنظیم کنید، برای مثال:
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;
نام کلاسها میتواند نامهای تحتاللفظی یا الگوهای glob باشد، برای مثال،
GCKUI\* و GCK\*Session.