این راهنمای توسعهدهنده نحوه افزودن پشتیبانی Google Cast را با استفاده از iOS Sender SDK به برنامه فرستنده iOS خود توضیح میدهد.
دستگاه تلفن همراه یا لپ تاپ فرستنده ای است که پخش را کنترل می کند و دستگاه Google Cast گیرنده ای است که محتوا را روی تلویزیون نمایش می دهد.
چارچوب فرستنده به کتابخانه باینری کلاس Cast و منابع مرتبط موجود در زمان اجرا بر روی فرستنده اشاره دارد. برنامه فرستنده یا برنامه Cast به برنامه ای اشاره دارد که روی فرستنده نیز اجرا می شود. برنامه Web Receiver به برنامه HTML در حال اجرا بر روی گیرنده وب اشاره دارد.
چارچوب فرستنده از یک طراحی پاسخ به تماس ناهمزمان برای اطلاع رسانی به برنامه فرستنده از رویدادها و انتقال بین حالت های مختلف چرخه عمر برنامه Cast استفاده می کند.
جریان برنامه
مراحل زیر جریان اجرای معمولی سطح بالا را برای یک برنامه فرستنده iOS توصیف می کند:
- چارچوب Cast
GCKDiscoveryManager
را بر اساس ویژگیهای ارائه شده درGCKCastOptions
راهاندازی میکند تا اسکن دستگاهها را آغاز کند. - هنگامی که کاربر روی دکمه Cast کلیک میکند، چارچوب گفتگوی Cast را با لیست دستگاههای Cast کشف شده نشان میدهد.
- وقتی کاربر یک دستگاه Cast را انتخاب میکند، چارچوب تلاش میکند تا برنامه Web Receiver را در دستگاه Cast راهاندازی کند.
- این چارچوب برای تأیید راهاندازی برنامه گیرنده وب، تماسهای برگشتی را در برنامه فرستنده فراخوانی میکند.
- این چارچوب یک کانال ارتباطی بین برنامههای فرستنده و گیرنده وب ایجاد میکند.
- این چارچوب از کانال ارتباطی برای بارگیری و کنترل پخش رسانه در گیرنده وب استفاده می کند.
- این فریم ورک حالت پخش رسانه را بین فرستنده و گیرنده وب همگام میکند: زمانی که کاربر اقدامات رابط کاربر فرستنده را انجام میدهد، فریم ورک آن درخواستهای کنترل رسانه را به گیرنده وب ارسال میکند و هنگامی که گیرنده وب بهروزرسانیهای وضعیت رسانه را ارسال میکند، فریم ورک وضعیت را بهروزرسانی میکند. رابط کاربر فرستنده
- هنگامی که کاربر برای قطع ارتباط از دستگاه Cast، روی دکمه Cast کلیک میکند، چارچوب برنامه فرستنده را از گیرنده وب قطع میکند.
برای عیب یابی فرستنده خود، باید ورود به سیستم را فعال کنید.
برای فهرستی جامع از همه کلاسها، روشها و رویدادها در چارچوب Google Cast iOS، به مرجع Google Cast iOS API مراجعه کنید. بخشهای زیر مراحل ادغام Cast در برنامه iOS شما را پوشش میدهند.
روش های فراخوانی از موضوع اصلی
زمینه Cast را راهاندازی کنید
چارچوب Cast دارای یک شی تکتنه جهانی به نام GCKCastContext
است که همه فعالیتهای چارچوب را هماهنگ میکند. این شی باید در اوایل چرخه عمر برنامه، معمولاً در روش -[application:didFinishLaunchingWithOptions:]
از نماینده برنامه، مقداردهی اولیه شود، به طوری که از سرگیری جلسه خودکار در راه اندازی مجدد برنامه فرستنده به درستی راه اندازی شود.
یک شی GCKCastOptions
باید هنگام مقداردهی اولیه GCKCastContext
ارائه شود. این کلاس شامل گزینه هایی است که بر رفتار فریم ورک تأثیر می گذارد. مهمترین آنها شناسه برنامه Web Receiver است که برای فیلتر کردن نتایج کشف و راه اندازی برنامه Web Receiver هنگام شروع جلسه 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 SDK این ویجتها را فراهم میکند که با فهرست چک طراحی Cast مطابقت دارند:
پوشش مقدماتی : کلاس
GCKCastContext
روشی دارد،presentCastInstructionsViewControllerOnceWithCastButton
، که می تواند برای برجسته کردن دکمه Cast در اولین باری که یک گیرنده وب در دسترس است استفاده شود. برنامه فرستنده می تواند متن، موقعیت متن عنوان و دکمه رد کردن را سفارشی کند.دکمه Cast : با شروع Cast iOS sender SDK 4.6.0، دکمه Cast همیشه وقتی دستگاه فرستنده به Wi-Fi متصل است قابل مشاهده است. اولین باری که کاربر پس از شروع اولیه برنامه، روی دکمه Cast ضربه میزند، یک گفتگوی مجوزها ظاهر میشود تا کاربر بتواند به برنامه دسترسی شبکه محلی را به دستگاههای موجود در شبکه بدهد. پس از آن، هنگامی که کاربر روی دکمه Cast ضربه میزند، یک گفتگوی ارسال نمایش داده میشود که دستگاههای کشف شده را فهرست میکند. هنگامی که کاربر در حالی که دستگاه متصل است، روی دکمه Cast ضربه میزند، متادیتای رسانه فعلی (مانند عنوان، نام استودیوی ضبط و یک تصویر کوچک) را نمایش میدهد یا به کاربر اجازه میدهد ارتباط خود را با دستگاه پخش قطع کند. هنگامی که کاربر روی دکمه Cast ضربه میزند در حالی که هیچ دستگاهی در دسترس نیست، صفحهای نمایش داده میشود که به کاربر اطلاعاتی درباره علت پیدا نشدن دستگاهها و نحوه عیبیابی نشان میدهد.
کنترلکننده کوچک : وقتی کاربر در حال ارسال محتوا است و از صفحه محتوای فعلی یا کنترلکننده گسترشیافته دور شده و به صفحه دیگری در برنامه فرستنده رفته است، مینی کنترلکننده در پایین صفحه نمایش داده میشود تا به کاربر اجازه دهد رسانه در حال ارسال را ببیند. ابرداده و کنترل پخش.
Expanded Controller : هنگامی که کاربر در حال ارسال محتوا است، اگر روی اعلان رسانه یا مینی کنترلر کلیک کند، کنترلر توسعه یافته راه اندازی می شود که متادیتای رسانه در حال پخش را نمایش می دهد و چندین دکمه برای کنترل پخش رسانه ارائه می دهد.
یک دکمه Cast اضافه کنید
این فریم ورک یک مؤلفه دکمه Cast را به عنوان یک زیر کلاس UIButton
ارائه می دهد. با قرار دادن آن در UIBarButtonItem
می توان آن را به نوار عنوان برنامه اضافه کرد. یک زیر کلاس معمولی UIViewController
می تواند یک دکمه Cast را به صورت زیر نصب کند:
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];
به طور پیش فرض، با ضربه زدن روی دکمه، کادر گفتگوی Cast که توسط فریمورک ارائه شده است باز می شود.
GCKUICastButton
همچنین می تواند مستقیماً به استوری بورد اضافه شود.
پیکربندی کشف دستگاه
در چارچوب، کشف دستگاه به طور خودکار اتفاق می افتد. نیازی به شروع یا توقف صریح فرآیند کشف نیست مگر اینکه یک رابط کاربری سفارشی را پیاده سازی کنید.
کشف در چارچوب توسط کلاس GCKDiscoveryManager
مدیریت می شود که یکی از ویژگی های GCKCastContext
است. چارچوب یک مؤلفه محاوره ای پیش فرض Cast برای انتخاب و کنترل دستگاه فراهم می کند. فهرست دستگاه از نظر واژگانی با نام مناسب دستگاه مرتب شده است.
نحوه عملکرد مدیریت جلسه
Cast SDK مفهوم جلسه Cast را معرفی می کند که ایجاد آن ترکیبی از مراحل اتصال به یک دستگاه، راه اندازی (یا پیوستن) یک برنامه گیرنده وب، اتصال به آن برنامه و راه اندازی یک کانال کنترل رسانه است. برای اطلاعات بیشتر در مورد جلسات Cast و چرخه عمر گیرنده وب، به راهنمای چرخه عمر برنامه گیرنده وب مراجعه کنید.
جلسات توسط کلاس GCKSessionManager
مدیریت می شوند که یکی از ویژگی های GCKCastContext
است. جلسات فردی با زیر کلاسهای کلاس GCKSession
نشان داده میشوند: برای مثال، GCKCastSession
جلسات را با دستگاههای Cast نشان میدهد. میتوانید به جلسه Cast فعال فعلی (در صورت وجود)، به عنوان ویژگی currentCastSession
GCKSessionManager
دسترسی داشته باشید.
رابط GCKSessionManagerListener
را می توان برای نظارت بر رویدادهای جلسه، مانند ایجاد جلسه، تعلیق، از سرگیری و خاتمه استفاده کرد. هنگامی که برنامه فرستنده به پسزمینه میرود، چارچوب بهطور خودکار جلسات را به حالت تعلیق در میآورد و زمانی که برنامه به پیشزمینه بازمیگردد، سعی میکند آنها را از سر بگیرد (یا پس از پایان غیرعادی/ ناگهانی برنامه در حالی که یک جلسه فعال بود، دوباره راهاندازی میشود).
اگر از کادر گفتگوی Cast استفاده می شود، در پاسخ به حرکات کاربر، جلسات ایجاد شده و به طور خودکار حذف می شوند. در غیر این صورت، برنامه می تواند جلسات را به طور صریح از طریق روش هایی در GCKSessionManager
شروع و پایان دهد.
اگر برنامه نیاز به پردازش خاصی در پاسخ به رویدادهای چرخه عمر جلسه داشته باشد، می تواند یک یا چند نمونه GCKSessionManagerListener
را با GCKSessionManager
ثبت کند. GCKSessionManagerListener
پروتکلی است که برای رویدادهایی مانند شروع جلسه، پایان جلسه و غیره، فراخوانی را تعریف می کند.
انتقال جریان
حفظ وضعیت جلسه اساس انتقال جریان است، جایی که کاربران میتوانند با استفاده از دستورات صوتی، برنامه Google Home یا نمایشگرهای هوشمند، جریانهای صوتی و تصویری موجود را در دستگاهها جابهجا کنند. پخش رسانه در یک دستگاه (منبع) متوقف می شود و در دستگاه دیگر (مقصد) ادامه می یابد. هر دستگاه Cast با آخرین سیستمافزار میتواند به عنوان منبع یا مقصد در انتقال جریان عمل کند.
برای دریافت دستگاه مقصد جدید در حین انتقال جریان، از ویژگی GCKCastSession#device
در طول پاسخ تماس [sessionManager:didResumeCastSession:]
استفاده کنید.
برای اطلاعات بیشتر به انتقال جریان در گیرنده وب مراجعه کنید.
اتصال مجدد خودکار
چارچوب Cast منطق اتصال مجدد را اضافه می کند تا به طور خودکار اتصال مجدد را در بسیاری از موارد گوشه ظریف کنترل کند، مانند:
- بهبودی از از دست دادن موقت WiFi
- بازیابی از خواب دستگاه
- بازیابی از پسزمینه برنامه
- در صورت خراب شدن برنامه بازیابی کنید
کنترل رسانه چگونه کار می کند
اگر یک جلسه Cast با یک برنامه گیرنده وب ایجاد شود که از فضای نام رسانه پشتیبانی می کند، یک نمونه از GCKRemoteMediaClient
به طور خودکار توسط چارچوب ایجاد می شود. می توان به عنوان ویژگی remoteMediaClient
نمونه GCKCastSession
به آن دسترسی داشت.
همه روشهای موجود در 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 فعلی فراهم می کند.
چارچوب Cast یک نوار کنترل به GCKUIMiniMediaControlsViewController
را ارائه میکند که میتواند به صحنههایی که میخواهید کنترلر کوچک را در آنها نشان دهید اضافه شود.
هنگامی که برنامه فرستنده شما در حال پخش جریانی زنده ویدیویی یا صوتی است، SDK به طور خودکار یک دکمه پخش/توقف را به جای دکمه پخش/مکث در کنترلر کوچک نمایش می دهد.
برای اینکه چگونه برنامه فرستنده شما می تواند ظاهر ویجت های Cast را پیکربندی کند، به سفارشی کردن رابط کاربر فرستنده iOS مراجعه کنید.
دو راه برای اضافه کردن کنترلر کوچک به برنامه فرستنده وجود دارد:
- به چارچوب Cast اجازه دهید طرحبندی کنترلکننده کوچک را با بستهکردن نمای کنترلکننده موجود با کنترلکننده مشاهده خود مدیریت کند.
- طرح بندی ویجت مینی کنترلر را خودتان با اضافه کردن آن به نمای کنترلر موجود خود با ارائه یک نمای فرعی در استوری بورد مدیریت کنید.
با استفاده از GCKUICastContainerViewController بسته بندی کنید
راه اول استفاده از GCKUICastContainerViewController
است که یک view controller دیگر را میپیچد و یک 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
پیاده سازی شده است.
اولین کاری که باید انجام دهید این است که کنترلر توسعه یافته پیش فرض را در زمینه Cast فعال کنید. برای فعال کردن کنترلر توسعه یافته پیش فرض، نماینده برنامه را تغییر دهید:
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 را پیکربندی کند، به Apply Custom Styles to Your App iOS مراجعه کنید.
کنترل صدا
چارچوب Cast به طور خودکار حجم برنامه فرستنده را مدیریت می کند. چارچوب به طور خودکار با حجم گیرنده وب برای ویجت های UI ارائه شده همگام می شود. برای همگامسازی یک نوار لغزنده ارائه شده توسط برنامه، از GCKUIDeviceVolumeController
استفاده کنید.
کنترل صدا دکمه فیزیکی
دکمه های فیزیکی صدا در دستگاه فرستنده را می توان برای تغییر صدای جلسه Cast در گیرنده وب با استفاده از پرچم physicalVolumeButtonsWillControlDeviceVolume
در GCKCastOptions
که در 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 را پایان دهد.
ورود به سیستم
GCKLogger
یک تکی است که برای لاگ کردن توسط فریمورک استفاده می شود. از GCKLoggerDelegate
برای سفارشی کردن نحوه مدیریت پیامهای گزارش استفاده کنید.
با استفاده از GCKLogger
، SDK خروجی ورود به سیستم را به شکل پیام های اشکال زدایی، خطاها و هشدارها تولید می کند. این پیامهای گزارش به اشکالزدایی کمک میکنند و برای عیبیابی و شناسایی مشکلات مفید هستند. به طور پیشفرض، خروجی گزارش متوقف میشود، اما با اختصاص یک GCKLoggerDelegate
، برنامه فرستنده میتواند این پیامها را از SDK دریافت کرده و آنها را به کنسول سیستم وارد کند.
@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
.