iOS アプリにキャストを統合する

このデベロッパー ガイドでは、iOS デバイスに Google Cast サポートを追加する方法について説明します。 iOS Sender SDK を使って送信する必要があります。

モバイル デバイスまたはノートパソコンが、再生を制御する送信者となり、 Google Cast デバイスがテレビにコンテンツを表示するレシーバーになります。

送信フレームワークは、Cast クラス ライブラリ バイナリを参照し、 リソースが含まれます。送信アプリまたはキャスト アプリ 送信者上でも動作しているアプリを指します。ウェブ レシーバー アプリ Web Receiver で実行される HTML アプリケーションのことを指します。

送信者フレームワークは、非同期コールバック設計を使用して送信者に通知します。 イベントのアプリ、キャストアプリの動作状態の切り替え サイクルです。

アプリケーションの流れ

次の手順は、送信者の一般的な実行フローの概要です。 iOS アプリ:

  • キャスト フレームワークが GCKDiscoveryManager データの特性に基づいて GCKCastOptions~ デバイスのスキャンを開始します。
  • ユーザーがキャスト ボタンをクリックすると、フレームワークによってキャストが表示されます。 ダイアログに、検出されたキャスト デバイスのリストが表示されます。
  • ユーザーがキャスト デバイスを選択すると、フレームワークはデバイスの起動を試行します。 キャスト デバイス上のウェブ レシーバー アプリ
  • フレームワークは送信側のアプリでコールバックを呼び出し、 Web Receiver アプリが起動されました。
  • フレームワークは、送信側と受信側のエンドポイントの間で ウェブレシーバーアプリ。
  • フレームワークは通信チャネルを使用してメディアを読み込み、制御します。 ウェブレシーバーで再生します。
  • フレームワークは、送信側と受信側との間でメディアの再生状態を同期します。 Web Receiver: ユーザーが送信者 UI アクションを実行すると、フレームワークは Web Receiver に送信されたメディア コントロール リクエストと、Web Receiver が メディア ステータスの更新を送信すると、フレームワークは送信側の UI の状態を更新します。
  • ユーザーがキャスト ボタンをクリックしてキャスト デバイスとの接続を解除すると、 フレームワークによって、送信者アプリと Web Receiver の接続が解除されます。

送信者のトラブルシューティングを行うには、ロギングを有効にする必要があります。

Google Cast のすべてのクラス、メソッド、イベントを網羅したリスト Google Cast iOS API をご覧ください。 リファレンスをご覧ください。以降のセクションでは をご覧ください。

メインスレッドからメソッドを呼び出す

キャスト コンテキストを初期化する

キャスト フレームワークには、グローバル シングルトン オブジェクトである GCKCastContext: フレームワークのすべてのアクティビティを調整します。このオブジェクトは初期化する必要があります アプリケーションのライフサイクルの早い段階で、 -[application:didFinishLaunchingWithOptions:] メソッドを呼び出しているため、 送信側のアプリの再起動時に自動的にセッションが再開されるようにする必要があります。

GCKCastOptions GCKCastContext を初期化する際は、オブジェクトを指定する必要があります。 このクラスには、フレームワークの動作に影響を与えるオプションが含まれています。最も その中でも重要なのが Web Receiver アプリケーション ID です。 キャスト セッションの開始時にウェブ レシーバー アプリを起動できます。 開始しました。

-[application:didFinishLaunchingWithOptions:] メソッドもおすすめ フレームワークからロギング メッセージを受信するためのロギング デリゲートを設定します。 これらはデバッグやトラブルシューティングに役立ちます。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
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)
    }
  }
}
<ph type="x-smartling-placeholder">
</ph>
Objective-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 Design に準拠したウィジェットが用意されています。 チェックリスト:

  • 導入オーバーレイ: GCKCastContext クラスには、次のメソッドがあります。 presentCastInstructionsViewControllerOnceWithCastButton、 Web Receiver が初めて実装されたときに、キャスト アイコンにスポットライトを当てるために使用できます。 を利用できます。送信側アプリは、テキストとタイトルの位置をカスタマイズできる 閉じるボタンもあります。

  • キャスト アイコン: Cast iOS Sender SDK 4.6.0 以降、キャスト アイコンが常に表示される 送信元のデバイスが Wi-Fi に接続されているときに通知が送られます。ユーザーが初めてタップしたとき キャスト アイコン、権限ダイアログ、 が表示され、ユーザーはアプリのローカル ネットワークから 通信できます。その後、ユーザーがキャスト アイコンをタップすると、キャストが 検出されたデバイスの一覧を示すダイアログが表示されます。ユーザーが すると、現在のキャスト アイコンが メディアのメタデータ(タイトル、レコーディング スタジオの名前、サムネイルなど) キャスト デバイスとの接続を解除できます。ユーザーが 視聴可能なデバイスがないときにキャスト アイコンをタップした場合、 デバイスが見つからない理由を示す情報が表示される トラブルシューティング方法についても学習しました

  • ミニ コントローラ: ユーザーがコンテンツをキャスト中で、現在の画面から移動した場合 送信側のアプリで別の画面にコンテンツ ページが開いたら、 ミニ コントローラが表示され、ユーザーは 現在キャスト中のメディアのメタデータを確認したり、再生を操作したりできます。

  • 拡張コントローラ: ユーザーがコンテンツをキャストしているときに、ユーザーがメディア通知または 拡張コントローラが起動し、 現在再生中のメディア メタデータのほか、複数のボタンで メディアの再生。

キャスト アイコンを追加する

フレームワークでは、キャスト アイコン コンポーネントが UIButton サブクラスとして提供されています。機能 アプリのタイトルバーに追加するには、UIBarButtonItem でラップします。典型的な 次のように、UIViewController サブクラスでキャスト アイコンをインストールできます。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Swift
で確認できます。
let castButton = GCKUICastButton(frame: CGRect(x: 0, y: 0, width: 24, height: 24))
castButton.tintColor = UIColor.gray
navigationItem.rightBarButtonItem = UIBarButtonItem(customView: castButton)
<ph type="x-smartling-placeholder">
</ph>
Objective-C
GCKUICastButton *castButton = [[GCKUICastButton alloc] initWithFrame:CGRectMake(0, 0, 24, 24)];
castButton.tintColor = [UIColor grayColor];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:castButton];

デフォルトでは、ボタンをタップすると、 説明します。

GCKUICastButton ストーリーボードに直接追加することもできます

デバイスの検出を設定する

フレームワークでは、デバイスの検出は自動的に行われます。インフラストラクチャを 検出プロセスを明示的に開始または停止する(カスタム UI を実装していない限り)。

フレームワーク内の検出はクラスによって管理される GCKDiscoveryManager これは Pod の GCKCastContext。「 デバイス選択用のデフォルトのキャスト ダイアログ コンポーネントが、 できます。デバイスリストは、デバイスのわかりやすい名前で辞書順に並べ替えられます。

セッション管理の仕組み

Cast SDK には、キャスト セッションというコンセプト、 これは、デバイスへの接続、Web ブラウザの起動(またはウェブ レシーバアプリ、そのアプリへの接続、メディア コントロール チャネルの初期化。Web Receiver を確認する アプリケーション ライフサイクル ガイド をご覧ください。

セッションはクラスによって管理される GCKSessionManager これは Pod の GCKCastContext。 個々のセッションは、クラスのサブクラスで表される GCKSession: たとえば、 GCKCastSession キャスト デバイスによるセッションを表します。現在アクティブなキャストにアクセスできます セッション(存在する場合)を GCKSessionManagercurrentCastSession プロパティとして使用します。

GCKSessionManagerListener インターフェースを使用して、セッション作成、 停止、再開、終了ですフレームワークは自動的に 送信側のアプリがバックグラウンドに移動して再開を試みたときに、 アプリがフォアグラウンドに戻ったとき(または (セッションがアクティブだったときにアプリが異常終了した、またはアプリが中断されるなど)。

キャスト ダイアログが使用されている場合、セッションが作成されて破棄される 自動的に適用されます。それ以外の場合、アプリの起動と終了は 明示的に許可するセッションを GCKSessionManager

アプリでセッションのライフサイクルに応じて特別な処理を行う必要がある場合 イベントを処理すると、1 つ以上の GCKSessionManagerListener インスタンスを GCKSessionManagerGCKSessionManagerListener は、サービス アカウントを定義する セッション開始、セッション終了などのイベントに対するコールバックを呼び出せます。

ストリーミング転送

セッション状態の保持はストリーム転送の基礎であり、 音声コマンドや Google Home を使って、既存の音声ストリームや動画ストリームをデバイス間で移動できます。 アプリ、スマートディスプレイ。メディアの再生を別のデバイス(ソース)で停止し、別のデバイス(ソース)で続行する あります。最新のファームウェアを搭載したキャスト デバイスは、デバイスのソースまたは宛先として機能できます。 ストリーム転送

ストリームの転送中に新しい宛先デバイスを取得するには、次のコマンドを使用します。 GCKCastSession#device 使用し、 [sessionManager:didResumeCastSession:] 呼び出すことができます。

詳しくは、 ウェブレシーバーでのストリーミング転送 をご覧ください。

自動再接続

キャスト フレームワークは再接続を自動的に処理するための再接続ロジックを追加 次のような多くの微妙な特殊なケースで使用します。

  • Wi-Fi の一時的な切断から復旧する
  • デバイスのスリープからの復帰
  • アプリをバックグラウンドから復元する
  • アプリがクラッシュした場合を復元する

メディア コントロールの仕組み

メディアに対応している Web Receiver アプリでキャスト セッションが確立されている場合 Namespace に GCKRemoteMediaClient フレームワークによって自動的に作成されます。「kubectl get pod my-test-app」 次の remoteMediaClient プロパティ: GCKCastSession 作成します。

Web Receiver にリクエストを発行する GCKRemoteMediaClient のすべてのメソッド は GCKRequest オブジェクトで、 リクエストを追跡できます GCKRequestDelegate 割り当てられて、結果に関する通知を受け取ることができます。 表示されます。

GCKRemoteMediaClient のインスタンスは、 アプリの複数の部分、実際には一部の内部コンポーネントで共有される場合があります。 キャスト ダイアログやミニ メディア コントロールなどのフレームワークでは、 作成します。そのために、GCKRemoteMediaClient では、複数の GCKRemoteMediaClientListener

メディア メタデータを設定する

GCKMediaMetadata クラスは、キャストするメディア アイテムに関する情報を表します。次の この例では、映画の新しい GCKMediaMetadata インスタンスを作成し、タイトルを設定します。 サブタイトル、レコーディング スタジオ名、2 つの画像があります。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
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))
<ph type="x-smartling-placeholder">
</ph>
Objective-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 を使用できます。 受信機で実行されるメディア プレーヤー アプリの制御(再生、 一時停止、停止できます。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
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
}
<ph type="x-smartling-placeholder">
</ph>
Objective-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 Pod の現在のインスタンスを GCKVideoInfo。 このインスタンスには、HDR TV 形式のタイプと、幅と高さが含まれています。 ピクセルです。4K 形式のバリアントは、hdrType プロパティで列挙型で示されます。 値は GCKVideoInfoHDRType です。

ミニ コントローラを追加する

Cast デザイン チェックリスト 送信側アプリは、mini データ管理者 ユーザーが現在のコンテンツ ページから移動したときに表示されます。 ミニ コントローラを使用すると、すぐにアクセスでき、 現在のキャスト セッション。

キャスト フレームワークにはコントロール バー、 GCKUIMiniMediaControlsViewController は、ミニ コントローラを表示するシーンに追加できます。

送信側アプリが動画や音声のライブ配信を再生しているときに、SDK は 再生/一時停止ボタンの代わりに再生/停止ボタンを自動的に表示する 確認できます。

詳しくは、iOS の送信者 UI をカスタマイズするをご覧ください。 送信側アプリは、キャスト ウィジェットの外観を設定できます。

ミニ コントローラを送信アプリに追加する方法は 2 つあります。

  • ラッピングにより、Cast フレームワークにミニ コントローラのレイアウトを管理させる 独自のビュー コントローラを使用できるようになります。
  • ミニ コントローラ ウィジェットのレイアウトをご自身で管理するには、 既存のビュー コントローラには、ストーリーボードにサブビューを配置できます。

GCKUICastContainerViewController を使用してラップする

1 つ目の方法は、 GCKUICastContainerViewController これは、別のビュー コントローラをラップして、 GCKUIMiniMediaControlsViewController ] をクリックします。この方法には、カスタム スコープをカスタマイズできない コンテナ ビュー コントローラの動作は構成できません。

この最初の方法は通常、 アプリ デリゲートの -[application:didFinishLaunchingWithOptions:] メソッド:

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
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()

  ...
}
<ph type="x-smartling-placeholder">
</ph>
Objective-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];
  ...

}
をご覧ください。 <ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
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
    }
  }
}
<ph type="x-smartling-placeholder">
</ph>
Objective-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

既存のビュー コントローラに埋め込む

2 つ目は、ミニ コントローラを既存のビューに直接追加する方法です。 コントローラで createMiniMediaControlsViewController 作成してみましょう。 GCKUIMiniMediaControlsViewController コンテナのビュー コントローラにサブビューとして追加できます。

アプリ デリゲートでビュー コントローラをセットアップします。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
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
}
<ph type="x-smartling-placeholder">
</ph>
Objective-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 を作成します。 コンテナのビュー コントローラにサブビューとして追加します。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
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)
    }
  }

...
<ph type="x-smartling-placeholder">
</ph>
Objective-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 は、ミニ コントローラを表示するタイミングをホスト ビュー コントローラに指示します。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Swift
で確認できます。
  func miniMediaControlsViewController(_: GCKUIMiniMediaControlsViewController,
                                       shouldAppear _: Bool) {
    updateControlBarsVisibility()
  }
<ph type="x-smartling-placeholder">
</ph>
Objective-C
- (void)miniMediaControlsViewController:
            (GCKUIMiniMediaControlsViewController *)miniMediaControlsViewController
                           shouldAppear:(BOOL)shouldAppear {
  [self updateControlBarsVisibility];
}

拡張コントローラを追加

Google Cast デザイン チェックリストでは、送信側アプリで拡張 データ管理者 。拡張コントローラは全画面表示で ミニコントローラです

展開されたコントローラは全画面表示で、 リモート メディア再生このビューにより、キャストアプリは ウェブレシーバーの音量レベルを除き、キャスト セッションを管理しやすい セッションのライフサイクル(キャストの接続/停止)を設定できます。また、Kubernetes の メディア セッションに関するステータス情報(アートワーク、タイトル、サブタイトルなど) 参照)。

このビューの機能は、 GCKUIExpandedMediaControlsViewController クラスです。

まず、デフォルトの拡張コントローラを有効にします コンテキストをキャストします。アプリのデリゲートを変更して、デフォルトの拡張コントローラを有効にします。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Swift
で確認できます。
func applicationDidFinishLaunching(_ application: UIApplication) {
  ..

  GCKCastContext.sharedInstance().useDefaultExpandedMediaControls = true

  ...
}
<ph type="x-smartling-placeholder">
</ph>
Objective-C
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  ...

  [GCKCastContext sharedInstance].useDefaultExpandedMediaControls = YES;

  ..
}

次のコードをビュー コントローラに追加して、拡張コントローラを読み込みます。 ユーザーが動画のキャストを開始したとき:

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Swift
で確認できます。
func playSelectedItemRemotely() {
  GCKCastContext.sharedInstance().presentDefaultExpandedMediaControls()

  ...

  // Load your media
  sessionManager.currentSession?.remoteMediaClient?.loadMedia(mediaInformation)
}
<ph type="x-smartling-placeholder">
</ph>
Objective-C
- (void)playSelectedItemRemotely {
  [[GCKCastContext sharedInstance] presentDefaultExpandedMediaControls];

  ...

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

拡張コントローラは、ユーザーが起動したときにも自動的に起動します。 ミニ コントローラをタップします。

送信側アプリが動画や音声のライブ配信を再生しているときに、SDK は 再生/一時停止ボタンの代わりに再生/停止ボタンを自動的に表示する 表示されます

カスタム スタイルを iOS に適用する アプリ をご覧ください。

音量調節

送信側アプリの音量は、キャスト フレームワークによって自動的に管理されます。「 の Web Receiver ボリュームと自動的に同期します。 提供します。アプリのスライダーを同期するには、次のコマンドを使用します。 GCKUIDeviceVolumeController

物理ボタンの音量調節

送信側のデバイスの物理的な音量ボタンを使用して、 キャスト セッションの音量を調節できます。 次に関する physicalVolumeButtonsWillControlDeviceVolume フラグ: GCKCastOptions, 設定されます。 GCKCastContext

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Swift
で確認できます。
let criteria = GCKDiscoveryCriteria(applicationID: kReceiverAppID)
let options = GCKCastOptions(discoveryCriteria: criteria)
options.physicalVolumeButtonsWillControlDeviceVolume = true
GCKCastContext.setSharedInstanceWith(options)
<ph type="x-smartling-placeholder">
</ph>
Objective-C
GCKDiscoveryCriteria *criteria = [[GCKDiscoveryCriteria alloc]
                                          initWithApplicationID:kReceiverAppID];
GCKCastOptions *options = [[GCKCastOptions alloc]
                                          initWithDiscoveryCriteria :criteria];
options.physicalVolumeButtonsWillControlDeviceVolume = YES;
[GCKCastContext setSharedInstanceWithOptions:options];

エラーを処理する

送信側アプリですべてのエラー コールバックを処理し、 Cast のライフサイクルの各ステージで最適なレスポンスを判断できます。アプリは エラー ダイアログをユーザーに表示するか、キャスト セッションの終了を決定できます。

ロギング

GCKLogger フレームワークによるロギングに使用されるシングルトン。こちらの GCKLoggerDelegate ログメッセージの処理方法をカスタマイズできます。

SDK は GCKLogger を使用して、ロギング出力をデバッグ形式で生成します。 エラー、警告があります。これらのログメッセージはデバッグに役立ち、 問題の特定に役立ちますデフォルトでは、ログ出力は 抑制されていますが、GCKLoggerDelegate を割り当てると、送信側アプリは これらのメッセージを SDK から送信し、システム コンソールに記録できます。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
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)
    }
  }
}
<ph type="x-smartling-placeholder">
</ph>
Objective-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

デバッグ メッセージと詳細メッセージも有効にするには、次の行をコードの後に追加します。 委任の設定(上記で表示):

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Swift
で確認できます。
let filter = GCKLoggerFilter.init()
filter.minimumLevel = GCKLoggerLevel.verbose
GCKLogger.sharedInstance().filter = filter
<ph type="x-smartling-placeholder">
</ph>
Objective-C
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init];
[filter setMinimumLevel:GCKLoggerLevelVerbose];
[GCKLogger sharedInstance].filter = filter;

Cloud Logging によって生成されるログ メッセージを GCKLogger。 クラスごとに最小ロギングレベルを設定します。次に例を示します。

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph>
Swift
で確認できます。
let filter = GCKLoggerFilter.init()
filter.setLoggingLevel(GCKLoggerLevel.verbose, forClasses: ["GCKUICastButton",
                                                            "GCKUIImageCache",
                                                            "NSMutableDictionary"])
GCKLogger.sharedInstance().filter = filter
<ph type="x-smartling-placeholder">
</ph>
Objective-C
GCKLoggerFilter *filter = [[GCKLoggerFilter alloc] init];
[filter setLoggingLevel:GCKLoggerLevelVerbose
             forClasses:@[@"GCKUICastButton",
                          @"GCKUIImageCache",
                          @"NSMutableDictionary"
                          ]];
[GCKLogger sharedInstance].filter = filter;

クラス名は、リテラル名または glob パターンのいずれかにできます。たとえば、 GCKUI\*GCK\*Session