Cast'i iOS Uygulamanıza Entegre Edin

Bu geliştirici kılavuzunda, iOS Sender SDK'yı kullanarak iOS gönderen uygulamanıza Google Cast desteğini nasıl ekleyeceğiniz açıklanmaktadır.

Mobil cihaz veya dizüstü bilgisayar, oynatmayı kontrol eden gönderendir, Google Cast cihazı ise TV'de içeriği gösteren alıcıdır.

Gönderen çerçevesi, Cast sınıf kitaplığı ikili programını ve gönderenin çalışma zamanında mevcut olan ilişkili kaynakları ifade eder. Gönderen uygulaması veya Cast uygulaması, gönderen üzerinde de çalışan bir uygulamayı belirtir. Web Alıcı uygulaması, Web Alıcısı'nda çalışan HTML uygulamasını belirtir.

Gönderen çerçevesi, gönderen uygulamasına etkinlikler hakkında bilgi vermek ve Cast uygulaması yaşam döngüsünün çeşitli durumları arasında geçiş yapmak için eşzamansız bir geri çağırma tasarımı kullanır.

Uygulama akışı

Aşağıdaki adımlarda, gönderen iOS uygulaması için tipik üst düzey yürütme akışı açıklanmaktadır:

  • Cast çerçevesi, cihazları taramaya başlamak için GCKCastOptions bölümünde sağlanan özelliklere göre GCKDiscoveryManager başlatılır.
  • Kullanıcı Yayınla düğmesini tıkladığında çerçeve, Yayınla iletişim kutusunu, bulunan Yayın cihazlarının listesini gösterir.
  • Kullanıcı bir Yayın cihazı seçtiğinde çerçeve, Yayın cihazında Web Alıcı uygulamasını başlatmaya çalışır.
  • Çerçeve, Web Alıcı uygulamasının başlatıldığını onaylamak için gönderen uygulamasında geri çağırmaları çağırır.
  • Çerçeve, gönderen ile Web Alıcı uygulamaları arasında bir iletişim kanalı oluşturur.
  • Çerçeve, Web Alıcısında medya oynatmayı yüklemek ve kontrol etmek için iletişim kanalını kullanır.
  • Çerçeve, medya oynatma durumunu gönderen ve Web Alıcı arasında senkronize eder: Kullanıcı, gönderenin kullanıcı arayüzü işlemleri yaptığında çerçeve bu medya kontrol isteklerini Web Alıcısı'na iletir. Web Alıcısı medya durumu güncellemeleri gönderdiğinde ise çerçeve, gönderen kullanıcı arayüzünün durumunu günceller.
  • Kullanıcı, yayın cihazı bağlantısını kesmek için Yayın düğmesini tıkladığında çerçeve, gönderen uygulamasının Web Alıcısı ile bağlantısını keser.

Gönderenle ilgili sorunları gidermek için günlük kaydını etkinleştirmeniz gerekir.

Google Cast iOS çerçevesindeki tüm sınıfların, yöntemlerin ve etkinliklerin kapsamlı listesi için Google Cast iOS API Referansı'na bakın. Aşağıdaki bölümlerde Cast'i iOS uygulamanıza entegre etme adımları açıklanmaktadır.

Ana iş parçacığındaki arama yöntemleri

Yayın bağlamını başlatın

Cast çerçevesi, çerçevenin tüm etkinliklerini koordine eden GCKCastContext adlı küresel bir tek nesneye sahiptir. Bu nesnenin, uygulamanın yaşam döngüsünün başlarında (genellikle uygulama temsilcisinin -[application:didFinishLaunchingWithOptions:] yönteminde) başlatılması gerekir. Böylece gönderen uygulaması yeniden başlatıldığında otomatik oturum devam ettirme doğru şekilde tetiklenebilir.

GCKCastContext başlatılırken GCKCastOptions nesnesi sağlanmalıdır. Bu sınıf, çerçevenin davranışını etkileyen seçenekler içerir. Bunlardan en önemlisi, keşif sonuçlarını filtrelemek ve bir Yayınlama oturumu başlatıldığında Web Alıcı uygulamasını başlatmak için kullanılan Web Alıcısı uygulama kimliğidir.

-[application:didFinishLaunchingWithOptions:] yöntemi, çerçeveden günlük kaydı mesajlarını alacak günlük kaydı yetkisi ayarlamak için de iyi bir yerdir. Bunlar hata ayıklama ve sorun giderme açısından faydalı olabilir.

Swift
@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)
    }
  }
}
Hedef-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 kullanıcı deneyimi widget'ları

Cast iOS SDK'sı, Cast Tasarımı Kontrol Listesi'ne uygun olan şu widget'ları sağlar:

  • Tanıtım Yerleşimi: GCKCastContext sınıfında, bir Web Alıcısı ilk kez kullanılabilir olduğunda Yayınla düğmesini ön plana çıkarmak için kullanılabilen bir presentCastInstructionsViewControllerOnceWithCastButton yöntemi bulunur. Gönderen uygulaması metni, başlık metninin konumunu ve Kapat düğmesini özelleştirebilir.

  • Yayınla Düğmesi: Cast iOS gönderen SDK 4.6.0 sürümünden itibaren, gönderen cihazı kablosuz ağa bağlıyken yayınla düğmesi her zaman görünür. Kullanıcı uygulamayı başlattıktan sonra Yayın düğmesine ilk kez dokunduğunda, kullanıcının uygulamaya ağdaki cihazlara yerel ağ erişimi izni verebilmesi için izinler iletişim kutusu görüntülenir. Ardından, kullanıcı yayın düğmesine dokunduğunda, bulunan cihazların listelendiği bir yayın iletişim kutusu gösterilir. Kullanıcı, cihaz bağlıyken yayın düğmesine dokunduğunda, geçerli medya meta verilerini (başlık, kayıt stüdyosunun adı ve küçük resim gibi) gösterir veya kullanıcının yayın cihazıyla bağlantısını kesmesine olanak tanır. Kullanıcı, kullanılabilir cihaz olmadığında yayın düğmesine dokunduğunda, cihazın neden bulunamadığından ve nasıl sorun giderileceğiyle ilgili bilgilerin yer aldığı bir ekran gösterilir.

  • Mini Kumanda: Kullanıcı içerik yayınlarken mevcut içerik sayfasından veya genişletilmiş denetleyiciden gönderen uygulamasında başka bir ekrana geçerse kullanıcının o an yayınlanan medya meta verilerini görmesine ve oynatmayı kontrol etmesine olanak tanımak için ekranın alt kısmında mini kumanda görüntülenir.

  • Genişletilmiş Denetleyici: Kullanıcı içerik yayınlarken medya bildirimini veya mini kumandayı tıkladığında genişletilmiş denetleyici açılır. Burada oynatılan medya meta verileri gösterilir ve medya oynatma işlemini kontrol etmek için birkaç düğme bulunur.

Yayınla düğmesi ekle

Çerçeve, bir UIButton alt sınıfı olarak Yayınla düğmesi bileşeni sağlar. UIBarButtonItem içine sarılarak uygulamanın başlık çubuğuna eklenebilir. Tipik bir UIViewController alt sınıfı aşağıdaki gibi bir Yayınla düğmesi yükleyebilir:

Swift
let castButton = GCKUICastButton(frame: CGRect(x: 0, y: 0, width: 24, height: 24))
castButton.tintColor = UIColor.gray
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
Hedef-C
GCKUICastButton *castButton = [[GCKUICastButton alloc] initWithFrame:CGRectMake(0, 0, 24, 24)];
castButton.tintColor = [UIColor grayColor];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:castButton];

Varsayılan olarak, düğmeye dokunduğunuzda çerçeve tarafından sağlanan Yayınla iletişim kutusu açılır.

GCKUICastButton ayrıca doğrudan film şeridine de eklenebilir.

Cihaz bulmayı yapılandırın

Bu çerçevede cihaz keşfi otomatik olarak gerçekleşir. Özel bir kullanıcı arayüzü uygulamadığınız sürece keşif işlemini açıkça başlatmanız veya durdurmanız gerekmez.

Çerçevedeki keşif, GCKCastContext özelliğinin özelliği olan GCKDiscoveryManager sınıfı tarafından yönetilir. Çerçeve, cihaz seçimi ve kontrolü için varsayılan bir Cast iletişim kutusu bileşeni sağlar. Cihaz listesi, cihaz dostu ada göre sözlüksel olarak sıralanır.

Oturum yönetiminin işleyiş şekli

Cast SDK'sı, bir cihaza bağlanma, bir Web Alıcısı uygulamasını başlatma (veya katılma) adımlarını birleştiren, bu uygulamaya bağlanma ve medya kontrol kanalını başlatma adımlarını birleştiren Cast oturumu kavramını tanıtır. Yayınlama oturumları ve Web Alıcısı yaşam döngüsü hakkında daha fazla bilgi için Web Alıcısı Uygulama yaşam döngüsü kılavuzuna bakın.

Oturumlar, GCKCastContext özelliğinin özelliği olan GCKSessionManager sınıfı tarafından yönetilir. Bağımsız oturumlar, GCKSession sınıfının alt sınıflarıyla temsil edilir: Örneğin, GCKCastSession, yayın cihazlarıyla yapılan oturumları temsil eder. Şu anda etkin olan Cast oturumuna (varsa) GCKSessionManager öğesinin currentCastSession özelliği olarak erişebilirsiniz.

GCKSessionManagerListener arayüzü; oturum oluşturma, askıya alma, devam ettirme ve sonlandırma gibi oturum etkinliklerini izlemek için kullanılabilir. Çerçeve, gönderen uygulaması arka plana geçerken oturumları otomatik olarak askıya alır ve uygulama ön plana geri döndüğünde (veya oturum etkinken anormal/ani bir uygulama sonlandırıldıktan sonra yeniden başlatılırsa) oturumları devam ettirmeye çalışır.

Yayınla iletişim kutusu kullanılıyorsa oturumlar oluşturulur ve kullanıcı hareketlerine göre otomatik olarak kesilir. Aksi takdirde, uygulama oturumları GCKSessionManager üzerindeki yöntemler aracılığıyla açıkça başlatabilir ve sonlandırabilir.

Uygulamanın, oturum yaşam döngüsü etkinliklerine yanıt olarak özel işlem yapması gerekiyorsa GCKSessionManager ile bir veya daha fazla GCKSessionManagerListener örneği kaydedebilir. GCKSessionManagerListener, oturum başlangıcı, oturum sonu gibi etkinlikler için geri çağırmaları tanımlayan bir protokoldür.

Akış aktarma

Akış aktarımının temeli oturum durumunu korumaktır. Kullanıcılar burada sesli komutları, Google Home uygulamasını veya akıllı ekranları kullanarak mevcut ses ve video akışlarını cihazlar arasında taşıyabilir. Medya, bir cihazda (kaynak) durdurulur ve başka bir cihazda (hedef) devam eder. En yeni donanım yazılımına sahip yayın cihazları, akış aktarımında kaynak veya hedef olarak kullanılabilir.

Akış aktarımı sırasında yeni hedef cihazı almak için [sessionManager:didResumeCastSession:] geri çağırması sırasında GCKCastSession#device mülkünü kullanın.

Daha fazla bilgi için Web Alıcısında akış aktarımı bölümüne bakın.

Otomatik yeniden bağlanma

Cast çerçevesi, aşağıdaki gibi çok zor fark edilen köşe durumlarında yeniden bağlantıyı otomatik olarak işlemek için yeniden bağlanma mantığı ekler:

  • Geçici kablosuz ağ kaybından kurtulma
  • Cihazı uyku modundan kurtar
  • Uygulamayı arka plana alma durumundan kurtar
  • Uygulama kilitlenirse kurtar

Medya kontrolünün işleyiş şekli

Medya ad alanını destekleyen bir Web Alıcı uygulamasıyla yayınlama oturumu oluşturulursa çerçeve tarafından otomatik olarak GCKRemoteMediaClient örneği oluşturulur. Bu örneğe GCKCastSession örneğinin remoteMediaClient özelliği olarak erişilebilir.

GCKRemoteMediaClient ürününde Web Alıcısına istek gönderen tüm yöntemler, bu isteği izlemek için kullanılabilecek bir GCKRequest nesnesi döndürür. İşlemin nihai sonucu hakkında bildirimler almak için bu nesneye bir GCKRequestDelegate atanabilir.

GCKRemoteMediaClient örneğinin, uygulamanın birden çok bölümü tarafından paylaşılmış olması beklenir. Gerçekten de Cast iletişim kutusu ve mini medya kontrolleri gibi çerçevenin bazı dahili bileşenleri bu örneği paylaşır. Bu amaçla GCKRemoteMediaClient, birden fazla GCKRemoteMediaClientListener öğesinin kaydedilmesini destekler.

Medya meta verilerini ayarla

GCKMediaMetadata sınıfı, yayınlamak istediğiniz medya öğesiyle ilgili bilgileri temsil eder. Aşağıdaki örnek, bir filmin yeni GCKMediaMetadata örneğini oluşturur ve başlığı, alt başlığı, kayıt stüdyosunun adını ve iki resmi ayarlar.

Swift
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))
Hedef-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]];

Medya meta verileri içeren resimlerin kullanımı hakkında Resim Seçimi ve Önbelleğe Alma bölümüne bakın.

Medya yükle

Bir medya öğesi yüklemek için medyanın meta verilerini kullanarak GCKMediaInformation örneği oluşturun. Ardından mevcut GCKCastSession değerini alın ve GCKRemoteMediaClient ayarını alıcı uygulamaya yüklemek için GCKRemoteMediaClient kullanın. Daha sonra, alıcıda çalışan bir medya oynatıcı uygulamasını (oynatma, duraklatma ve durdurma gibi) kontrol etmek için GCKRemoteMediaClient kullanabilirsiniz.

Swift
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
}
Hedef-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;
}

Ayrıca medya kanallarını kullanma ile ilgili bölüme de bakın.

4K video biçimi

Medyanızın hangi video biçimini gösterdiğini belirlemek için GCKMediaStatus öğesinin videoInfo özelliğini kullanarak GCKVideoInfo öğesinin mevcut örneğini alın. Bu örnek, HDR TV biçiminin türünü ve yüksekliği ile genişliği piksel cinsinden içerir. 4K biçiminin varyantları hdrType özelliğinde GCKVideoInfoHDRType numaralandırma değerleriyle belirtilir.

Mini kumanda ekle

Yayın Tasarımı Kontrol Listesi'ne göre bir gönderen uygulaması, kullanıcı mevcut içerik sayfasından ayrıldığında görünmesi gereken mini denetleyici olarak bilinen kalıcı bir denetim sağlamalıdır. Mini kumanda, anlık erişim sağlar ve mevcut yayın oturumu için görünür bir hatırlatıcı sağlar.

Cast çerçevesi, mini kumandayı göstermek istediğiniz sahnelere eklenebilecek bir kontrol çubuğu (GCKUIMiniMediaControlsViewController) sağlar.

Gönderen uygulamanız video veya ses canlı yayını oynatırken SDK, mini kumandadaki oynat/duraklat düğmesi yerine otomatik olarak bir oynat/durdur düğmesi görüntüler.

Gönderen uygulamanızın Cast widget'larının görünümünü nasıl yapılandırabileceğini öğrenmek için iOS Gönderen Kullanıcı Arayüzünü özelleştirme bölümüne bakın.

Mini kumandayı gönderen uygulamasına iki şekilde ekleyebilirsiniz:

  • Mevcut görünüm denetleyicinizi kendi görünüm denetleyicisiyle sarmalayarak Cast çerçevesinin mini kumandanın düzenini yönetmesine izin verin.
  • Mini kumanda widget'ının düzenini resimli taslak için alt görünüm sağlayarak mevcut görüntüleme denetleyicinize ekleyerek kendiniz yönetin.

GCKUICastContainerViewController'ı kullanarak sarmalama

İlki, başka bir görünüm denetleyicisini sarmalayan ve en alta GCKUIMiniMediaControlsViewController ekleyen GCKUICastContainerViewController kullanmaktır. Bu yaklaşım, animasyonu özelleştiremeyeceğiniz ve kapsayıcı görünümü denetleyicisinin davranışını yapılandıramayacağınız için sınırlıdır.

Bu ilk yöntem genellikle uygulama temsilcisinin -[application:didFinishLaunchingWithOptions:] yönteminde yapılır:

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

  ...
}
Hedef-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];
  ...

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

Mevcut görünüm denetleyiciye yerleştir

İkinci yöntem ise createMiniMediaControlsViewController kullanarak GCKUIMiniMediaControlsViewController örneği oluşturup bunu container görünümü denetleyicisine alt görünüm olarak ekleyerek mini kumandayı doğrudan mevcut görünüm denetleyicinize eklemektir.

Uygulama yetkisinde görüntüleme denetleyicinizi ayarlayın:

Swift
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
}
Hedef-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;
}

Kök görünüm denetleyicinizde bir GCKUIMiniMediaControlsViewController örneği oluşturun ve bunu kapsayıcı görünümü denetleyicisine alt görünüm olarak ekleyin:

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

...
Hedef-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, mini kumandanın ne zaman görünür olması gerektiğini ana makine görünüm denetleyicisine bildirir:

Swift
  func miniMediaControlsViewController(_: GCKUIMiniMediaControlsViewController,
                                       shouldAppear _: Bool) {
    updateControlBarsVisibility()
  }
Hedef-C
- (void)miniMediaControlsViewController:
            (GCKUIMiniMediaControlsViewController *)miniMediaControlsViewController
                           shouldAppear:(BOOL)shouldAppear {
  [self updateControlBarsVisibility];
}

Genişletilmiş denetleyici ekle

Google Cast Tasarım Kontrol Listesi için bir gönderen uygulamasının, yayınlanan medya için genişletilmiş denetleyici sağlaması gerekir. Genişletilmiş kumanda, mini kumandanın tam ekran sürümüdür.

Genişletilmiş kumanda, uzaktan medya oynatmanın tam kontrolünü sunan tam ekran görünümüdür. Bu görünüm, bir yayın uygulamasının Web Alıcı ses seviyesi kontrolü ve oturum yaşam döngüsü (bağlama/yayını durdurma) hariç olmak üzere bir yayın oturumunun yönetilebilir her aşamasını yönetmesine izin vermelidir. Ayrıca, medya oturumuyla ilgili tüm durum bilgilerini de (poster, başlık, alt başlık vb.) sağlar.

Bu görünümün işlevi, GCKUIExpandedMediaControlsViewController sınıfı tarafından uygulanır.

Yapmanız gereken ilk şey, yayın bağlamında varsayılan genişletilmiş denetleyiciyi etkinleştirmektir. Uygulama temsilcinizi, varsayılan genişletilmiş denetleyiciyi etkinleştirecek şekilde değiştirin:

Swift
func applicationDidFinishLaunching(_ application: UIApplication) {
  ..

  GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true

  ...
}
Hedef-C
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  ...

  [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES;

  ..
}

Kullanıcı video yayınlamaya başladığında genişletilmiş denetleyiciyi yüklemek için görünüm denetleyicinize aşağıdaki kodu ekleyin:

Swift
func playSelectedItemRemotely() {
  GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()

  ...

  // Load your media
  sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInformation)
}
Hedef-C
- (void)playSelectedItemRemotely {
  [[GCKCastContext sharedInstance] presentDefaultExpandedMediaControls];

  ...

  // Load your media
  [self.sessionManager.currentSession.remoteMediaClient loadMedia:mediaInformation];
}

Kullanıcı mini kumandaya dokunduğunda da genişletilmiş kumanda otomatik olarak başlatılır.

Gönderen uygulamanız bir video veya ses canlı yayını oynatırken SDK, genişletilmiş kumandadaki oynat/duraklat düğmesi yerine otomatik olarak bir oynat/durdur düğmesi görüntüler.

Gönderen uygulamanızın Cast widget'larının görünümünü nasıl yapılandırabileceğini öğrenmek için iOS Uygulamanıza Özel Stiller Uygulama bölümüne bakın.

Ses düzeyi kontrolü

Cast çerçevesi, gönderen uygulaması için ses düzeyini otomatik olarak yönetir. Çerçeve, sağlanan kullanıcı arayüzü widget'ları için Web Alıcı birimi ile otomatik olarak senkronize edilir. Uygulama tarafından sağlanan kaydırma çubuğunu senkronize etmek için GCKUIDeviceVolumeController değerini kullanın.

Fiziksel düğme ses düzeyi kontrolü

Gönderen cihazın üzerindeki fiziksel ses düğmeleri, GCKCastContext üzerinde ayarlanan GCKCastOptions üzerindeki physicalVolumeButtonsWillControlDeviceVolume işareti kullanılarak Web Alıcısı'ndaki yayın oturumunun ses düzeyini değiştirmek için kullanılabilir.

Swift
let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID)
let options = GCKCastOptions(discoveryCriteria: criteria)
options.physicalVolumeButtonsWillControlDeviceVolume = true
GCKCastContext.setSharedInstanceWith(options)
Hedef-C
GCKDiscoveryCriteria *criteria = [[GCKDiscoveryCriteria alloc]
                                          initWithApplicationID:kReceiverAppID];
GCKCastOptions *options = [[GCKCastOptions alloc]
                                          initWithDiscoveryCriteria :criteria];
options.physicalVolumeButtonsWillControlDeviceVolume = YES;
[GCKCastContext setSharedInstanceWithOptions:options];

Hataları işleme

Gönderen uygulamalarının tüm hata geri çağırmalarını ele alması ve Cast yaşam döngüsünün her aşaması için en iyi yanıta karar vermesi çok önemlidir. Uygulama, kullanıcıya hata iletişim kutuları gösterebilir veya Cast oturumunu sonlandırmaya karar verebilir.

Günlük Kaydı

GCKLogger, çerçeve tarafından günlük kaydı için kullanılan bir single'dır. Günlük mesajlarını işleme şeklinizi özelleştirmek için GCKLoggerDelegate öğesini kullanın.

SDK, GCKLogger öğesini kullanarak hata ayıklama mesajları, hatalar ve uyarılar biçiminde günlük kaydı çıkışı oluşturur. Bu günlük mesajları, hata ayıklamaya yardımcı olmanın yanı sıra sorun giderme ve tespit etme açısından kullanışlıdır. Varsayılan olarak, günlük çıkışı atlanır. Ancak bir GCKLoggerDelegate atandığında gönderen uygulama bu mesajları SDK'dan alabilir ve sistem konsoluna kaydedebilir.

Swift
@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)
    }
  }
}
Hedef-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

Hata ayıklama mesajlarını ve ayrıntılı mesajları da etkinleştirmek için yetki verilmiş kullanıcıyı ayarladıktan sonra şu satırı koda ekleyin (daha önce gösterilmiştir):

Swift
let filter = GCKLoggerFilter.init()
filter.minimumLevel = GCKLoggerLevel.verbose
GCKLogger.sharedInstance().filter = filter
Hedef-C
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init];
[filter setMinimumLevel:GCKLoggerLevelVerbose];
[GCKLogger sharedInstance].filter = filter;

GCKLogger tarafından oluşturulan günlük mesajlarını da filtreleyebilirsiniz. Her sınıf için minimum günlük kaydı seviyesini belirleyin. Örneğin:

Swift
let filter = GCKLoggerFilter.init()
filter.setLoggingLevel(GCKLoggerLevel.verbose, forClasses: ["GCKUICastButton",
                                                            "GCKUIImageCache",
                                                            "NSMutableDictionary"])
GCKLogger.sharedInstance().filter = filter
Hedef-C
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init];
[filter setLoggingLevel:GCKLoggerLevelVerbose
             forClasses:@[@"GCKUICastButton",
                          @"GCKUIImageCache",
                          @"NSMutableDictionary"
                          ]];
[GCKLogger sharedInstance].filter = filter;

Sınıf adları, düz adlar veya glob kalıpları olabilir (örneğin, GCKUI\* ve GCK\*Session).