Как добавить продвинутые функции в приложение для iOS

Рекламные паузы

iOS Sender SDK поддерживает рекламные паузы и сопутствующие объявления в медиапотоке.

Дополнительную информацию о том, как работают рекламные паузы, можно найти в обзоре рекламных пауз веб-приемника.

Хотя рекламные паузы можно задавать как на отправителе, так и на получателе, рекомендуется задавать их на веб-приемнике и приемнике Android TV, чтобы обеспечить согласованное поведение на разных платформах.

В iOS укажите рекламные паузы в команде загрузки с помощью GCKAdBreakClipInfo и GCKAdBreakInfo:

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]];

Изменение скорости воспроизведения

Приложение может показывать и изменять скорость воспроизведения текущего мультимедийного объекта. Вы можете задать скорость воспроизведения с помощью метода -[setPlaybackRate:] или -[setPlaybackRate:customData:] класса GCKRemoteMediaClient, получить доступ к объекту GCKUIPlaybackRateController с помощью метода playbackRateController класса GCKUIMediaController и показать текущую скорость воспроизведения с помощью метода playbackRate класса GCKUIPlaybackRateController.

Образец кода

В следующих двух файлах реализован класс 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

Канал можно зарегистрировать в любое время. Если сеанс не подключен, канал автоматически подключится, когда сеанс будет подключен, при условии, что пространство имен канала присутствует в списке поддерживаемых пространств имен метаданных приложения веб-приемника.

Каждый пользовательский канал определяется уникальным пространством имен и должен начинаться с префикса 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);
}

Чтобы задать логику, которая должна выполняться при подключении или отключении определенного канала, переопределите методы -[didConnect] и -[didDisconnect], если вы используете GCKCastChannel, или предоставьте реализации для методов -[castChannelDidConnect:] и -[castChannelDidDisconnect:] класса GCKGenericChannelDelegate, если вы используете GCKGenericChannel.

Поддержка автовоспроизведения

Подробнее об API автовоспроизведения и очереди…

Как переопределить выбор и кеширование изображений

Различные компоненты фреймворка (диалоговое окно Cast, мини-контроллер, расширенный контроллер и GCKUIMediaController, если он настроен) будут показывать обложку для транслируемого медиаконтента. URL изображений обычно включаются в GCKMediaMetadata для медиаконтента, но у приложения-отправителя может быть альтернативный источник URL.

Протокол GCKUIImagePicker определяет способ выбора подходящего изображения для заданного использования и желаемого размера. У него есть один метод – -[getImageWithHints:fromMetadata:], который принимает в качестве параметров объекты GCKUIImageHints и GCKMediaMetadata и возвращает объект GCKImage. Фреймворк предоставляет реализацию GCKUIImagePicker по умолчанию, которая всегда выбирает первое изображение из списка в объекте GCKMediaMetadata. Однако приложение может использовать альтернативную реализацию, если задать свойство imagePicker синглтона GCKCastContext.

Протокол GCKUIImageCache также определяет способ кеширования изображений, скачанных фреймворком по протоколу HTTPS. Фреймворк предоставляет реализацию GCKUIImageCache по умолчанию, которая сохраняет скачанные графические файлы в каталоге кеша приложения. Однако приложение может предоставлять альтернативную реализацию, задавая свойство imageCache синглтона GCKCastContext.

Дальнейшие действия

На этом мы заканчиваем обзор функций, которые можно добавить в приложение-отправитель для iOS. Теперь вы можете создать приложение-отправитель для другой платформы (Android или веб-приложение) или веб-приложение-приемник.