iOS 앱에 고급 기능 추가

광고 시점

iOS Sender SDK는 특정 미디어 스트림 내에서 광고 시점 및 컴패니언 광고를 지원합니다.

광고 시점의 작동 방식에 관한 자세한 내용은 웹 수신기 광고 시점 개요를 참고하세요.

중단은 보낸 사람과 받는 사람 모두에서 지정할 수 있지만 웹 수신기Android TV 수신기에서 지정하여 플랫폼 간에 일관된 동작을 유지하는 것이 좋습니다.

iOS에서는 다음과 같이 GCKAdBreakClipInfoGCKAdBreakInfo를 사용하여 로드 명령어에 광고 시점을 지정합니다.

Swift
let breakClip1Builder = GCKAdBreakClipInfoBuilder(adBreakClipID: "bc0")
breakClip1Builder.title = "Clip title"
if let posterUrl = URL(string: "https://www.some.url") {
  breakClip1Builder.posterURL = posterUrl
}
breakClip1Builder.duration = 60
breakClip1Builder.whenSkippable = 5  // Set this field so that the ad is skippable
let breakClip1 = breakClip1Builder.build()

let breakClip2 = ...
let breakClip3 = ...


let break1 = GCKAdBreakInfoBuilder(adBreakID: "b0", adBreakClipIds: ["bc0", "bc1", "bc2"]).build()
let mediaInfoBuilder = GCKMediaInformationBuilder(entity: "entity")
...
mediaInfoBuilder.adBreaks = [break1]
mediaInfoBuilder.adBreakClips = [breakClip1, breakClip2, breakClip3]
...
mediaInformation = mediaInfoBuilder.build()

let mediaLoadRequestDataBuilder = GCKMediaLoadRequestDataBuilder()
mediaLoadRequestDataBuilder.mediaInformation = mediaInformation

sessionManager.currentSession?.remoteMediaClient?.loadMedia(with: mediaLoadRequestDataBuilder.build())
Objective-C
GCKAdBreakClipInfoBuilder *breakClipInfoBuilder = [[GCKAdBreakClipInfoBuilder alloc] initWithAdBreakClipID:@"bc0"];
breakClipInfoBuilder.title = @"Clip title";
breakClipInfoBuilder.posterURL = [[NSURL alloc] initWithString:@"https://www.some.url"];
breakClipInfoBuilder.duration = 60;
breakClipInfoBuilder.whenSkippable = 5;
GCKAdBreakClipInfo *breakClip1 = breakClipInfoBuilder.build;

GCKAdBreakClipInfo *breakClip2 = ...
GCKAdBreakClipInfo *breakClip3 = ...

GCKAdBreakInfo *break1 = [[GCKAdBreakInfoBuilder alloc] initWithAdBreakID:@"b0"
                                                           adBreakClipIds:@[@"bc0", @"bc1", @"bc2"]].build;

GCKMediaInformationBuilder *mediaInfoBuilder = [[GCKMediaInformationBuilder alloc]
                                                initWithEntity:@"entity"];
...
mediaInfoBuilder.adBreaks = @[break1];
mediaInfoBuilder.adBreakClips = @[breakClip1, breakClip2, breakClip3];
...
self.mediaInformation = [mediaInfoBuilder build];

GCKMediaLoadRequestDataBuilder *mediaLoadRequestDataBuilder = [[GCKMediaLoadRequestDataBuilder alloc] init];
mediaLoadRequestDataBuilder.mediaInformation = self.mediaInformation;

// Send a load request to the remote media client.
GCKRequest *request = [self.sessionManager.currentSession.remoteMediaClient
                                loadMediaWithLoadRequestData:[mediaLoadRequestDataBuilder build]];

가변 재생 속도

앱은 현재 미디어 항목의 재생 속도를 표시하고 변경할 수 있습니다. GCKRemoteMediaClient-[setPlaybackRate:] 또는 -[setPlaybackRate:customData:]를 사용하여 속도를 설정하고 GCKUIMediaControllerplaybackRateController를 사용하여 GCKUIPlaybackRateController에 액세스하며 GCKUIPlaybackRateControllerplaybackRate를 사용하여 현재 재생 속도를 표시할 수 있습니다.

샘플 코드

다음 두 파일은 '일반', '절반 속도', '배속' 버튼이 있는 분할된 컨트롤을 사용하여 재생 속도를 제어하는 GCKUIPlaybackRateController를 구현합니다.

Swift
import GoogleCast

/**
 * An implementation of GCKUIPlaybackRateController that controls playback rate
 * using a segmented control that has "normal", "half speed", and "double speed"
 * buttons.
 */
class SegmentedButtonPlaybackRateController: GCKUIPlaybackRateController {
  static let kSegmentNormal = 0;
  static let kSegmentHalfSpeed = 1;
  static let kSegmentDoubleSpeed = 2;

  var segmentedControl: UISegmentedControl!

  override var playbackRate: Float {
    didSet {
      var buttonIndex = 0

      // Map the playback rate to one of our three supported speeds.
      if playbackRate == 1.0 {
        buttonIndex = SegmentedButtonPlaybackRateController.kSegmentNormal
      } else if playbackRate < 1.0 {
        buttonIndex = SegmentedButtonPlaybackRateController.kSegmentHalfSpeed
      } else {
        buttonIndex = SegmentedButtonPlaybackRateController.kSegmentDoubleSpeed
      }

      segmentedControl?.selectedSegmentIndex = buttonIndex
    }
  }
  override var inputEnabled: Bool {
    didSet {
      segmentedControl?.isEnabled = inputEnabled
    }
  }

  /**
   * Designated initializer.
   *
   * @param segmentedControl The segmented control for changing/displaying the
   * playback rate.
   */
  convenience init(_ segmentedControl: UISegmentedControl) {
    self.init()
    self.segmentedControl = segmentedControl;

    segmentedControl.addTarget(self,
                               action: #selector(segmentedControlTapped(sender:)),
                               for: UIControl.Event.valueChanged)
  }

  @objc func segmentedControlTapped(sender: UISegmentedControl) {
    var playbackRate: Float = 1.0

    switch segmentedControl?.selectedSegmentIndex {
    case SegmentedButtonPlaybackRateController.kSegmentHalfSpeed:
      playbackRate = 0.5;
    case SegmentedButtonPlaybackRateController.kSegmentDoubleSpeed:
      playbackRate = 2.0;
    case SegmentedButtonPlaybackRateController.kSegmentNormal:
      fallthrough
    default:
      playbackRate = 1.0;
    }

    self.playbackRate = playbackRate
  }
}
Objective-C

SegmentedButtonPlaybackRateController.h

#import <GoogleCast/GoogleCast.h>
#import <UIKit/UIKit.h>

/**
 * An implementation of GCKUIPlaybackRateController that controls playback rate
 * using a segmented control that has "normal", "half speed", and "double speed"
 * buttons.
 */
@interface SegmentedButtonPlaybackRateController : GCKUIPlaybackRateController

/**
 * Designated initializer.
 *
 * @param segmentedControl The segmented control for changing/displaying the
 * playback rate.
 */
- (instancetype)initWithSegmentedControl:(UISegmentedControl *)segmentedControl;

@end

SegmentedButtonPlaybackRateController.m

#import "SegmentedButtonPlaybackRateController.h"

@interface SegmentedButtonPlaybackRateController () {
  UISegmentedControl *_segmentedControl;
}

@end

static const NSInteger kSegmentNormal = 0;
static const NSInteger kSegmentHalfSpeed = 1;
static const NSInteger kSegmentDoubleSpeed = 2;

@implementation SegmentedButtonPlaybackRateController

- (instancetype)initWithSegmentedControl:(UISegmentedControl *)segmentedControl {
  if (self = [super init]) {
    _segmentedControl = segmentedControl;
    [_segmentedControl addTarget:self
                          action:@selector(segmentedControlTapped:)
                forControlEvents:UIControlEventValueChanged];
  }
  return self;
}

- (void)setPlaybackRate:(float)playbackRate {
  [super setPlaybackRate:playbackRate];

  NSInteger buttonIndex = 0;

  // Map the playback rate to one of our three supported speeds.
  if (playbackRate == 1.0) {
    buttonIndex = kSegmentNormal;
  } else if (playbackRate < 1.0) {
    buttonIndex = kSegmentHalfSpeed;
  } else {
    buttonIndex = kSegmentDoubleSpeed;
  }

  _segmentedControl.selectedSegmentIndex = buttonIndex;
}

- (void)setInputEnabled:(BOOL)inputEnabled {
  _segmentedControl.enabled = inputEnabled;
  [super setInputEnabled:inputEnabled];
}

- (void)segmentedControlTapped:(id)sender {
  float playbackRate;

  switch (_segmentedControl.selectedSegmentIndex) {
    case kSegmentHalfSpeed:
      playbackRate = 0.5;
      break;

    case kSegmentDoubleSpeed:
      playbackRate = 2.0;
      break;

    case kSegmentNormal:
    default:
      playbackRate = 1.0;
      break;
  }

  self.playbackRate = playbackRate;
}

@end

맞춤 채널 추가

Cast 프레임워크는 웹 수신기에 맞춤 메시지를 보내는 채널을 만드는 두 가지 방법을 제공합니다.

  1. GCKCastChannel는 연결된 상태가 있는 중요한 채널을 구현하기 위해 서브클래스화되어야 합니다.
  2. GCKGenericChannel는 서브클래스화의 대안으로 제공됩니다. 다른 곳에서 처리될 수 있도록 수신된 메시지를 대리자에게 전달합니다.

다음은 GCKCastChannel 구현의 예입니다.

Swift
class HGCTextChannel: GCKCastChannel {
  override func didReceiveTextMessage(_ message: String) {
    print("received message: \(message)")
  }
}
Objective-C

HGCTextChannel.h

#import <GoogleCast/GCKCastChannel.h>

@interface HGCTextChannel : GCKCastChannel

@end

HGCTextChannel.m

#import "HGCTextChannel.h"

@implementation HGCTextChannel
- (void)didReceiveTextMessage:(NSString*)message {
  NSLog(@"received message: %@", message);
}

@end

채널은 언제든지 등록할 수 있습니다. 세션이 현재 연결된 상태가 아니면 채널은 세션 자체가 연결될 때 자동으로 연결됩니다. 단, 채널의 네임스페이스가 Web Receiver 앱 메타데이터의 지원되는 네임스페이스 목록에 있어야 합니다.

각 커스텀 채널은 고유한 네임스페이스로 정의되며 urn:x-cast: 접두사로 시작해야 합니다(예: urn:x-cast:com.example.custom). 각각 고유한 네임스페이스를 갖는 여러 맞춤 채널을 가질 수 있습니다. 웹 수신기 앱은 동일한 네임스페이스를 사용하여 메시지를 주고받을 수도 있습니다.

Swift
var error: GCKError?
let textChannel = HGCTextChannel.init(namespace: "urn:x-cast:com.google.cast.sample.helloworld")
sessionManager.currentCastSession?.add(textChannel)
textChannel.sendTextMessage("Hello World", error: &error)

if error != nil {
  print("Error sending text message \(error.debugDescription)")
}
Objective-C
NSError *error;
HGCTextChannel *textChannel = [[HGCTextChannel alloc] initWithNamespace:@"urn:x-cast:com.google.cast.sample.helloworld"];
[sessionManager.currentCastSession addChannel:textChannel];
[textChannel sendTextMessage:@"Hello World"
                       error:&error];

if (error != nil) {
  NSLog(@"Error sending text message: %@", error);
}

특정 채널이 연결되거나 연결 해제될 때 실행해야 하는 로직을 제공하려면 GCKCastChannel를 사용하는 경우 -[didConnect]-[didDisconnect] 메서드를 재정의하고 GCKGenericChannel를 사용하는 경우 GCKGenericChannelDelegate-[castChannelDidConnect:]-[castChannelDidDisconnect:] 메서드 구현을 제공합니다.

자동재생 지원

자동재생 및 대기열 API를 참고하세요.

이미지 선택 및 캐싱 재정의

프레임워크의 다양한 구성요소 (즉, 전송 대화상자, 미니 컨트롤러, 확장된 컨트롤러, 구성된 경우 GCKUIMediaController)는 현재 전송 중인 미디어의 아트워크를 표시합니다. 이미지 아트워크의 URL은 일반적으로 미디어의 GCKMediaMetadata에 포함되지만 발신기 앱에 URL의 대체 소스가 있을 수 있습니다.

GCKUIImagePicker 프로토콜은 지정된 용도와 원하는 크기에 적합한 이미지를 선택하는 방법을 정의합니다. 이 클래스에는 GCKUIImageHints 객체와 GCKMediaMetadata 객체를 매개변수로 사용하고 GCKImage 객체를 반환하는 단일 메서드 -[getImageWithHints:fromMetadata:]가 있습니다. 프레임워크는 항상 GCKMediaMetadata 객체의 이미지 목록에서 첫 번째 이미지를 선택하는 GCKUIImagePicker의 기본 구현을 제공하지만, 앱은 GCKCastContext 싱글톤의 imagePicker 속성을 설정하여 대체 구현을 제공할 수 있습니다.

GCKUIImageCache 프로토콜은 또한 HTTPS를 사용하여 프레임워크에서 다운로드한 이미지를 캐싱하는 방법을 정의합니다. 프레임워크는 다운로드한 이미지 파일을 앱의 캐시 디렉터리에 저장하는 GCKUIImageCache의 기본 구현을 제공하지만, 앱은 GCKCastContext 싱글톤의 imageCache 속성을 설정하여 대체 구현을 제공할 수 있습니다.

다음 단계

iOS Sender 앱에 추가할 수 있는 기능이 완료되었습니다. 이제 다른 플랫폼(Android 또는 )용 발신자 앱을 빌드하거나 웹 수신기를 빌드할 수 있습니다.