הוספת תכונות מתקדמות לאפליקציה ל-iOS

הפסקות למודעות

ה-SDK של iOS Sender תומך בהפסקות למודעות ובמודעות נלוות זרם מדיה נתון.

לצפייה סקירה כללית של הפסקות למודעות אצל מקלטי אינטרנט מידע על אופן הפעולה של הפסקות למודעות.

אפשר לציין הפסקות גם אצל השולח וגם אצל המקבל, אבל מומלץ שהן יופיעו שצוינו ב-Web Acceptr המקלט של Android TV לשמירה על עקביות התנהגות המשתמשים בפלטפורמות שונות.

ב-iOS, מציינים הפסקות למודעות בפקודת טעינה באמצעות GCKAdBreakClipInfo וגם GCKAdBreakInfo:

סוויפט
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())
יעד ג'
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, קצב ההפעלה באמצעות פקד מקטעים בעל 'רגיל', 'חצי מהירות', וגם "מהירות כפולה" לחצנים:

סוויפט
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
  }
}
יעד ג'

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:

סוויפט
class HGCTextChannel: GCKCastChannel {
  override func didReceiveTextMessage(_ message: String) {
    print("received message: \(message)")
  }
}
יעד ג'

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. זה כן אם יש מספר ערוצים מותאמים אישית, שלכל אחד מהם יש מרחב שמות ייחודי. האפליקציה 'מקלט אינטרנט' יכולה גם לשלוח ולקבל הודעות באמצעות אותו מרחב שמות.

סוויפט
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)")
}
יעד ג'
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:] של ה-methods GCKGenericChannelDelegate אם משתמשים ב-GCKGenericChannel.

תמיכה בהפעלה אוטומטית

לעיון בקטע הפעלה אוטומטית ו ממשקי API לרשימת תורים.

ביטול בחירה של תמונות ושמירה במטמון

רכיבים שונים במסגרת (למשל תיבת הדו-שיח של הפעלת Cast, לבקרה המורחבת GCKUIMediaController אם הוא מוגדר) יציג גרפיקה עבור המדיה שמופעלת כרגע בהעברה. כתובות ה-URL לגרפיקה של התמונה. בדרך כלל נכללות GCKMediaMetadata למדיה, אבל יכול להיות שלאפליקציית השולח יש מקור חלופי לכתובות ה-URL.

GCKUIImagePicker מגדיר אמצעי לבחירת תמונה מתאימה לשימוש מסוים. ובגודל הרצוי. יש לו method יחידה, -[getImageWithHints:fromMetadata:], שלוקחת GCKUIImageHints אובייקט, GCKMediaMetadata כפרמטרים, ומחזירה את הפונקציה GCKImage אובייקט תוצאה אחת. ה-framework מספק הטמעת ברירת מחדל של GCKUIImagePicker שבוחר תמיד את התמונה הראשונה ברשימת התמונות את האובייקט GCKMediaMetadata, אבל האפליקציה יכולה לספק חלופה על ידי הגדרת המאפיין imagePicker של GCKCastContext סינגלטון.

GCKUIImageCache מגדיר גם אמצעי לשמירה במטמון של תמונות שמורידים באמצעות HTTPS. ה-framework מספק הטמעת ברירת מחדל של GCKUIImageCache שבו קובצי תמונה שהורדו נשמרים במטמון של האפליקציה אבל האפליקציה יכולה לספק הטמעה חלופית על ידי הגדרה של imageCache של המאפיין GCKCastContext סינגלטון.

השלבים הבאים

הגענו למסקנה שאפשר להוסיף לאפליקציית השולח ב-iOS. עכשיו אפשר לפתח אפליקציית שולח לפלטפורמה אחרת (Android או אינטרנט), או ליצור WebReceiver.