Cast را در برنامه iOS خود ادغام کنید

این راهنمای توسعه‌دهنده نحوه افزودن پشتیبانی 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)
    }
  }
}
هدف-C

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)
هدف-C
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))
هدف-C
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
}
هدف-C
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()

  ...
}
هدف-C
- (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
    }
  }
}
هدف-C

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
}
هدف-C
- (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)
    }
  }

...
هدف-C

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()
  }
هدف-C
- (void)miniMediaControlsViewController:
            (GCKUIMiniMediaControlsViewController *)miniMediaControlsViewController
                           shouldAppear:(BOOL)shouldAppear {
  [self updateControlBarsVisibility];
}

اضافه کردن کنترلر توسعه یافته

چک لیست طراحی Google Cast به یک برنامه فرستنده نیاز دارد تا یک کنترل کننده گسترده برای رسانه در حال پخش ارائه دهد. کنترلر توسعه یافته یک نسخه تمام صفحه از مینی کنترلر است.

کنترلر گسترش یافته یک نمای تمام صفحه است که کنترل کامل پخش رسانه از راه دور را ارائه می دهد. این نما باید به یک برنامه ریخته گری اجازه دهد تا هر جنبه قابل مدیریت یک جلسه پخش را مدیریت کند، به استثنای کنترل حجم گیرنده وب و چرخه عمر جلسه (اتصال/توقف ارسال محتوا). همچنین تمام اطلاعات وضعیت جلسه رسانه (آثار هنری، عنوان، زیرنویس و غیره) را ارائه می دهد.

عملکرد این نما توسط کلاس GCKUIExpandedMediaControlsViewController پیاده سازی شده است.

اولین کاری که باید انجام دهید این است که کنترلر توسعه یافته پیش فرض را در زمینه Cast فعال کنید. برای فعال کردن کنترلر توسعه یافته پیش فرض، نماینده برنامه را تغییر دهید:

سویفت
func applicationDidFinishLaunching(_ application: UIApplication) {
  ..

  GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true

  ...
}
هدف-C
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  ...

  [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES;

  ..
}

کد زیر را به کنترل‌کننده مشاهده خود اضافه کنید تا وقتی کاربر شروع به پخش ویدیو می‌کند، کنترل‌کننده بازشده بارگیری شود:

سویفت
func playSelectedItemRemotely() {
  GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()

  ...

  // Load your media
  sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInformation)
}
هدف-C
- (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)
هدف-C
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)
    }
  }
}
هدف-C

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
هدف-C
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
هدف-C
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init];
[filter setLoggingLevel:GCKLoggerLevelVerbose
             forClasses:@[@"GCKUICastButton",
                          @"GCKUIImageCache",
                          @"NSMutableDictionary"
                          ]];
[GCKLogger sharedInstance].filter = filter;

نام کلاس ها می تواند نام های تحت اللفظی یا الگوهای glob باشد، به عنوان مثال، GCKUI\* و GCK\*Session .