Adicionar recursos avançados ao app iOS

Intervalos de anúncio

O SDK do remetente para iOS oferece suporte a intervalos e anúncios complementares em um determinado fluxo de mídia.

Consulte a Visão geral dos intervalos de anúncios do Web Receiver para mais informações sobre como eles funcionam.

Embora as interrupções possam ser especificadas no remetente e no receptor, é recomendável que elas sejam especificadas no Web Receiver e no Android TV Receiver para manter um comportamento consistente em todas as plataformas.

No iOS, especifique os intervalos de publicidade em um comando de carregamento usando GCKAdBreakClipInfo e 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]];

Velocidade de reprodução variável

Seu app pode mostrar e mudar a taxa de reprodução do item de mídia atual. É possível definir a taxa usando -[setPlaybackRate:] ou -[setPlaybackRate:customData:] do GCKRemoteMediaClient, acessar GCKUIPlaybackRateController usando playbackRateController do GCKUIMediaController, e mostrar a taxa de reprodução atual usando playbackRate do GCKUIPlaybackRateController.

Código de amostra

Os dois arquivos a seguir implementam GCKUIPlaybackRateController, que controla a taxa de reprodução usando um controle segmentado com botões "normal", "metade da velocidade" e "velocidade dupla":

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

Adicionar um canal personalizado

O framework do Cast oferece duas maneiras de criar um canal para enviar mensagens personalizadas a um Web Receiver:

  1. GCKCastChannel foi projetado para ser uma subclasse e implementar canais não triviais que têm estado associado.
  2. GCKGenericChannel é fornecido como uma alternativa à criação de subclasses. Ele transmite as mensagens recebidas a um delegado para que possam ser processadas em outro lugar.

Confira um exemplo de implementação de 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

Um canal pode ser registrado a qualquer momento. Se a sessão não estiver em um estado conectado, o canal será conectado automaticamente quando a sessão for conectada, desde que o namespace do canal esteja presente na lista de namespaces compatíveis dos metadados do app Web Receiver.

Cada canal personalizado é definido por um namespace exclusivo e precisa começar com o prefixo urn:x-cast:, por exemplo, urn:x-cast:com.example.custom. É possível ter vários canais personalizados, cada um com um namespace exclusivo. O app Web Receiver também pode enviar e receber mensagens usando o mesmo namespace.

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

Para fornecer uma lógica que precisa ser executada quando um canal específico é conectado ou desconectado, substitua os métodos -[didConnect] e -[didDisconnect] se estiver usando GCKCastChannel ou forneça implementações para os métodos -[castChannelDidConnect:] e -[castChannelDidDisconnect:] da GCKGenericChannelDelegate se estiver usando GCKGenericChannel.

Como oferecer suporte à reprodução automática

Consulte APIs de reprodução automática e fila.

Substituir a seleção e o armazenamento em cache de imagens

Vários componentes do framework (ou seja, a caixa de diálogo do Cast, o mini controlador, o controlador expandido e o GCKUIMediaController se configurado) vão mostrar a arte da mídia transmitida no momento. Os URLs para a arte da imagem geralmente são incluídos no GCKMediaMetadata da mídia, mas o app remetente pode ter uma fonte alternativa para os URLs.

O protocolo GCKUIImagePicker define uma maneira de selecionar uma imagem adequada para um determinado uso e tamanho desejado. Ele tem um único método, -[getImageWithHints:fromMetadata:], que usa um objeto GCKUIImageHints e um objeto GCKMediaMetadata como parâmetros e retorna um objeto GCKImage como um resultado. O framework fornece uma implementação padrão de GCKUIImagePicker, que sempre seleciona a primeira imagem na lista de imagens do objeto GCKMediaMetadata. No entanto, o app pode fornecer uma implementação alternativa definindo a propriedade imagePicker do singleton GCKCastContext.

O protocolo GCKUIImageCache também define uma maneira de armazenar em cache as imagens baixadas pelo framework usando HTTPS. O framework oferece uma implementação padrão de GCKUIImageCache, que armazena arquivos de imagem baixados no diretório de cache do app. No entanto, o app pode fornecer uma implementação alternativa definindo a propriedade imageCache do singleton GCKCastContext.

Próximas etapas

Assim, concluímos os recursos que podem ser adicionados ao app remetente do iOS. Agora você pode criar um app remetente para outra plataforma (Android ou Web) ou criar um Web Receiver.