Quick Start: Create a Simple TV Video App using Swift

Product(s)
Brightcove Player
Video Cloud
Role(s)
Device SDK Developer
Task(s)
Develop with the Native SDKs
Topic(s)
Code Samples
API(s)
Playback API
SDK
Get Started
tvOS

In this topic, you will learn how to build a simple video playback app using the Brightcove Player SDK for tvOS that will be playable on an Apple TV or the Xcode simulator. You will build it using the Swift programming language.

Overview

This example plays a video returned from the Brightcove Playback API, which is the latest and recommended API to retrieve content from your Video Cloud library.

This example plays videos from an internal array of video files.

To use the Playback API, you will need a Policy Key. If you are not familiar with Policy Keys, see the Policy API Overview.

Get started

Follow the steps below to get familiar with setting up an app project that uses the Brightcove Player SDK for tvOS. You can view the complete code for each of the following:

  1. AppDelegate
  2. ViewController

There are two ways to try out this sample:

Download the sample

Download the entire Xcode project for experimentation.

  1. Clone or download the Native SDK for iOS samples to your local system.
  2. Navigate to the Player/AppleTV/swift sample app.
  3. Run the pod install command.
  4. Open and run the newly created workspace.

Build the app by following the steps in this guide

Follow the steps below to get familiar with setting up an app project that uses the Brightcove Player SDK for tvOS. You can view the complete code for each of the following:

  1. AppDelegate
  2. ViewController

Create the project

Set up a project in Xcode. Then add the SDK along with any dependencies to the project.

Set up the Xcode project

Create a new Xcode project for the app.

  1. Start the creation of a new tvOS project in Xcode. Select Create a new Xcode project.

    Create project
    Create project
  2. Choose a tvOS Single View Application for the template and select Next.

    Choose project template
    Choose project template
  3. Set the project information as follows:

    • Product Name: Simple-Video-Playback
    • Team: none

      The Team field is optional. If you want to distribute your app on the App Store, you will need to select a team that you belong to through the Apple Developer Program. The team name is required for code signing. In this example, we'll select none.

    • Organization Name: your company name
    • Organization Identifier: com.example-company
      This makes the product name unique for the app store.
    • Language: Swift
    Add project information
    Add project information
  4. Choose the location where you want to save your project and create it.

    Save the project
    Save the project
  5. Now close the project (yes, close it — this is important!)

Add the SDK and its dependencies to your project

The easiest way to add the SDK and its dependencies to your project is to use CocoaPods.

CocoaPods is a dependency manager that adds libraries to your project. It is not required, but makes installation easier. To install CocoaPods, see the instructions on the CocoaPods site.

  1. In your project folder, create a plain text file called Podfile (no file extension).

  2. Using a text editor, add the following lines of code to the Podfile and save it. This code does the following:

    • Line 67: Defines the GitHub source.
    • Line 69: Sets Pods to use frameworks instead of static libraries.
    • Line 71: Defines the tvOS platform version.
    • Lines 73-75: Install the current version of the Brightcove player SDK.
    source 'https://github.com/brightcove/BrightcoveSpecs.git'
    
    use_frameworks!
    
    platform :tvos, '11.0' # (or whatever version you want)
    
    target 'Simple-Video-Playback' do
    	pod 'Brightcove-Player-Core/dynamic', '>= 6.3'
    end
  3. Open a Terminal session and navigate to your Simple-Video-Playback Xcode project folder.

    Terminal session
    Terminal session
  4. In the Terminal session, type the command

      pod install

    and press Return to run the it. You should see a series of messages in the terminal indicating that the Brightcove Player SDK has been added to your project.

  5. Notice the last line, which is important — from this point on, you must open the Simple-Video-Playback.xcworkspace file in Xcode, not the Simple-Video-Playback.xcodeproj file. The pod install command creates this .xcworkspace file for your project.

Code the video app

Create the code for a simple video playback app.

Set the audio behavior for the app

The audio session handles audio behavior at the app level. Learn more about the AVAudioSession class.

You can choose from several audio session categories and settings to customize your app's audio behavior. Choose the best audio session category for your app.

For this sample, we will use AVAudioSessionCategoryPlayback. This plays audio even when the screen is locked and with the Ring/Silent switch set to silent. To keep it simple, we will put the code for this in the App Delegate.

  1. In your project, open the App Delegate file (AppDelegate.swift).

  2. In the didFinishLaunchingWithOptions function, add code to set the audio session category. Make sure you import the AVFoundation framework.

    //
    //  AppDelegate.swift
    //  Simple-Video-Playback
    //
    //  Copyright © 2018 Brightcove. All rights reserved.
    //
    
    import UIKit
    import AVFoundation
    
    @UIApplicationMain
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var window: UIWindow?
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
            var categoryError :NSError?;
            var success: Bool;
            do {
                try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback);
                success = true;
            } catch let error as NSError {
                categoryError = error;
                success = false;
            }
    
            if !success {
                print("AppDelegate Debug - Error setting AVAudioSession category.  Because of this, there may be no sound. \(categoryError!)");
            }
    
            return true
        }
    
        func applicationWillResignActive(_ application: UIApplication) {
            // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
            // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
        }
    
        func applicationDidEnterBackground(_ application: UIApplication) {
            // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
            // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        }
    
        func applicationWillEnterForeground(_ application: UIApplication) {
            // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        }
    
        func applicationDidBecomeActive(_ application: UIApplication) {
            // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        }
    
        func applicationWillTerminate(_ application: UIApplication) {
            // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
        }
    
    }

Build the View Controller

Update the View Controller class to play a video from the Brightcove Playback API.

Update the View Controller class to play a video from a remote URL.

  1. In your project, open the View Controller file (ViewController.swift).

Import the Native SDK

Although the Brightcove Native Player SDK for iOS is written in Obj-C, we can simply import the framework modules into our Swift project.

  1. Below the existing import directive, add the following to import the Brightcove Native Player SDK:

    import BrightcovePlayerSDK

Customize the project with your values

Add values to access your Video Cloud account.

  1. Below the import directives, add your own values for the following:

    • Line 11: Defines your Brightcove Playback API Policy Key. This example plays a video returned from the Brightcove Playback API, which is the latest and recommended API to retrieve content from your Video Cloud library. If you are not familiar with Policy Keys, see the Policy API Overview.

    • Line 12: Defines your Video Cloud Account ID
    • Line 13: Defines your Video Cloud Video ID
    let kViewControllerPlaybackServicePolicyKey = "BCpkADawqM1W-vUOMe6RSA3pA6Vw-VWUNn5rL0lzQabvrI63-VjS93gVUugDlmBpHIxP16X8TSe5LSKM415UHeMBmxl7pqcwVY_AZ4yKFwIpZPvXE34TpXEYYcmulxJQAOvHbv2dpfq-S_cm"
    let kViewControllerAccountID = "3636334163001"
    let kViewControllerVideoID = "3666678807001"

Set the playback controller delegate

This allows your app to listen and respond to video playback events.

  1. Update the View Controller class to include the Brightcove playback controller delegate.

    class ViewController: UIViewController, BCOVPlaybackControllerDelegate {

Declare constants

  1. In the ViewController class, add the following :

    • Line 16: defines a variable for the view.
    • Line 18: Defines a variable for the TV UI, which will be set up in a later step.
    • Line 20: Defines a constant, which initializes the Brightcove playback service with your Account ID and Policy Key.
    • Line 22: Defines a constant for the Brightcove playback controller.

    class ViewController: UIViewController, BCOVPlaybackControllerDelegate                                                                                                                    {
        @IBOutlet weak var videoContainerView: UIView!
    
        var playerView: BCOVTVPlayerView?
    
        let playbackService = BCOVPlaybackService(accountId: kViewControllerAccountID, policyKey: kViewControllerPlaybackServicePolicyKey)
    
        let playbackController: BCOVPlaybackController = BCOVPlayerSDKManager.shared().createPlaybackController()

Create an init function

  1. Create an initfunction as follows:
    • Line 26: Calls the super class implementation of the init() function.
    • Line 28: Optional: Sends your Video Cloud Account ID to analytics. This is only needed if you override the BCOVVideo class or do not use the Brightcove Playback service or catalog.

    required init?(coder aDecoder: NSCoder)
      {
        super.init(coder: aDecoder)
    
        playbackController.analytics.account = kViewControllerAccountID;
      }

Configure the player

  1. In the viewDidLoad method add the following:

    • Line 35: calls a method to configure the TV player view.
    • Lines 38-40: set the delegate and turn on the auto-advance and autoplay features.
    • Line 43: links the playback controller to the player view.
    • Line 45: calls the requestContentFromPlaybackService function, which you will define in the next step.
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        createTVPlayerView()
    
        // Create and configure the playback controller
        playbackController.delegate = self
        playbackController.isAutoAdvance = true
        playbackController.isAutoPlay = true
    
        // Link the playback controller to the Player View
        playerView?.playbackController = playbackController
    
        requestContentFromPlaybackService()
    }

Create the player view

  1. Create a function named createTVPlayerView as follows:

    • Lines 34-39: ensure that the storyboard bindings are set.
    • Lines 43-44: set the presenting view controller.
    • Lines 47-51: create the player view and add it as a subview of the main view.
    func createTVPlayerView() {
    
        // Make sure storyboard bindings are set up
        self.loadViewIfNeeded()
        if (videoContainerView == nil)
        {
            print("videoContainerView not bound to storyboard")
            return
        }
    
        // Set ourself as the presenting view controller
        // so that tab bar panels can present other view controllers
        let options = BCOVTVPlayerViewOptions()
        options.presentingViewController = self
    
        // Create and add to the video container view
        playerView = BCOVTVPlayerView(options: options)
        if (playerView != nil) {
            playerView!.frame = self.videoContainerView.bounds
            self.videoContainerView.addSubview(playerView!)
        }
    }

Request content from the Brightcove library

In order to play back video content, you will request a playlist from the catalog service

  1. Create a function named requestContentFromPlaybackService as follows:

    • Lines 55-56: return a video object from the Playback API based on the given video id.
    • Line 60: adds the video to the playback controller.
    • Line 62: writes an error message if a playlist is not returned.
    func requestContentFromPlaybackService() {
      playbackService?.findVideo(withVideoID: kViewControllerVideoID, parameters: nil)
      { (video: BCOVVideo?, jsonResponse: [AnyHashable: Any]?, error: Error?) -> Void in
    
        if let v = video {
          //  since "isAutoPlay" is true, setVideos will begin playing the content
          self.playbackController.setVideos([v] as NSArray)
        } else {
          print("ViewController Debug - Error retrieving video: \(error?.localizedDescription ?? "unknown error")")
        }
      }
    }}

The rest

  1. Create functions to listen for the playback controller delegate methods, and functions for focus overrides.

    // MARK: Playback controller delegate methods
    
      func playbackController(_ controller: BCOVPlaybackController!, didAdvanceTo session: BCOVPlaybackSession!) {
          NSLog("ViewController Debug - Advanced to new session.")
      }
    
      func playbackController(_ controller: BCOVPlaybackController!, playbackSession session: BCOVPlaybackSession!, didReceive lifecycleEvent: BCOVPlaybackSessionLifecycleEvent!) {
          NSLog("Event: %@", lifecycleEvent.eventType)
      }
    
      // MARK: UIFocusEnvironment overrides
    
      // Focus Environment override for tvOS 9
      override var preferredFocusedView: UIView? {
          return playerView
      }
    
      // Focus Environment override for tvOS 10+
      override var preferredFocusEnvironments: [UIFocusEnvironment] {
          return (playerView != nil ? [ playerView! ] : [])
      }

View the code

The View Controller is now complete. Here is the full code:

//
//  ViewController.swift
//  Simple-Video-Playback
//
//  Copyright © 2018 Brightcove. All rights reserved.
//

import UIKit
import BrightcovePlayerSDK

let kViewControllerPlaybackServicePolicyKey = "BCpkADawqM3n0ImwKortQqSZCgJMcyVbb8lJVwt0z16UD0a_h8MpEYcHyKbM8CGOPxBRp0nfSVdfokXBrUu3Sso7Nujv3dnLo0JxC_lNXCl88O7NJ0PR0z2AprnJ_Lwnq7nTcy1GBUrQPr5e"
let kViewControllerAccountID = "4800266849001"
let kViewControllerVideoID = "5754208017001"

class ViewController: UIViewController, BCOVPlaybackControllerDelegate                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           {
    @IBOutlet weak var videoContainerView: UIView!

    var playerView: BCOVTVPlayerView?

    let playbackService = BCOVPlaybackService(accountId: kViewControllerAccountID, policyKey: kViewControllerPlaybackServicePolicyKey)

    let playbackController: BCOVPlaybackController = BCOVPlayerSDKManager.shared().createPlaybackController()

    required init?(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)

        playbackController.analytics.account = kViewControllerAccountID;
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        createTVPlayerView()

        // Create and configure the playback controller
        playbackController.delegate = self
        playbackController.isAutoAdvance = true
        playbackController.isAutoPlay = true

        // Link the playback controller to the Player View
        playerView?.playbackController = playbackController

        requestContentFromPlaybackService()
    }

    func createTVPlayerView() {

        // Make sure storyboard bindings are set up
        self.loadViewIfNeeded()
        if (videoContainerView == nil)
        {
            print("videoContainerView not bound to storyboard")
            return
        }

        // Set ourself as the presenting view controller
        // so that tab bar panels can present other view controllers
        let options = BCOVTVPlayerViewOptions()
        options.presentingViewController = self

        // Create and add to the video container view
        playerView = BCOVTVPlayerView(options: options)
        if (playerView != nil) {
            playerView!.frame = self.videoContainerView.bounds
            self.videoContainerView.addSubview(playerView!)
        }
    }

    func requestContentFromPlaybackService() {
        playbackService?.findVideo(withVideoID: kViewControllerVideoID, parameters: nil) { (video: BCOVVideo?, jsonResponse: [AnyHashable: Any]?, error: Error?) -> Void in

            if let v = video {
                //  since "isAutoPlay" is true, setVideos will begin playing the content
                self.playbackController.setVideos([v] as NSArray)
            } else {
                print("ViewController Debug - Error retrieving video: \(error?.localizedDescription ?? "unknown error")")
            }
        }
    }

    // MARK: Playback controller delegate methods

    func playbackController(_ controller: BCOVPlaybackController!, didAdvanceTo session: BCOVPlaybackSession!) {
        NSLog("ViewController Debug - Advanced to new session.")
    }

    func playbackController(_ controller: BCOVPlaybackController!, playbackSession session: BCOVPlaybackSession!, didReceive lifecycleEvent: BCOVPlaybackSessionLifecycleEvent!) {
        NSLog("Event: %@", lifecycleEvent.eventType)
    }

    // MARK: UIFocusEnvironment overrides

    // Focus Environment override for tvOS 9
    override var preferredFocusedView: UIView? {
        return playerView
    }

    // Focus Environment override for tvOS 10+
    override var preferredFocusEnvironments: [UIFocusEnvironment] {
        return (playerView != nil ? [ playerView! ] : [])
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Import the Native SDK

Although the Brightcove Native Player SDK for iOS is written in Obj-C, we can simply import the framework modules into our Swift project.

  1. Below the existing import directive, add the following to import the Brightcove Native Player SDK:

    import BrightcovePlayerSDK

Customize the project with your values

Define a variable with the value of your Account Id. This will be sent to Brightcove in a later step.

  1. Below the import directives, add your own value for your Brightcove Account Id.

    let kViewControllerAccountID = "your account id" // for analytics

Set the playback controller delegate

This allows your app to listen and respond to video playback events.

  1. Update the View Controller class to include the Brightcove playback controller delegate.

    class ViewController: UIViewController, BCOVPlaybackControllerDelegate {

Declare constants

  1. In the ViewController class, add the following :

    • Line 14: defines a variable for the view.
    • Line 16: Defines a variable for the TV UI, which will be set up in a later step.
    • Line 18: Defines a constant for the Brightcove playback controller.

    class ViewController: UIViewController, BCOVPlaybackControllerDelegate {
      @IBOutlet weak var videoContainerView: UIView!
    
      var playerView: BCOVTVPlayerView?
    
      let playbackController: BCOVPlaybackController = BCOVPlayerSDKManager.shared().createPlaybackController()

Create an init function

  1. Create an initfunction as follows:
    • Line 26: Calls the super class implementation of the init() function.
    • Line 28: Sends your Video Cloud Account ID to analytics. This registers your app with Brightcove.

      required init?(coder aDecoder: NSCoder)
      {
          super.init(coder: aDecoder)
    
          playbackController.analytics.account = kViewControllerAccountID;
      }

Configure the player

  1. In the viewDidLoad method add the following:

    • Lines 32-34: create an array of video sources using url paths.
    • Line 36: calls a method to configure the TV player view.
    • Lines 39-41: set the delegate and turn on the auto-advance and autoplay features.
    • Line 44: links the playback controller to the player view.
    • Line 46: adds the video array to the controller's playback queue, which is set for automatically start playing.
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    
        // create an array of videos
        var videoArray = [AnyObject]()
        videoArray = [videoWithURL(url: NSURL(string: "https://learning-services-media.brightcove.com/videos/hls/laughing_gull/laughing_gull.m3u8")!),
                      videoWithURL(url: NSURL(string: "https://learning-services-media.brightcove.com/videos/hls/greatblueheron/greatblueheron.m3u8")!)]
    
        createTVPlayerView()
    
        // Create and configure the playback controller
        playbackController.delegate = self
        playbackController.isAutoAdvance = true
        playbackController.isAutoPlay = true
    
        // Link the playback controller to the Player View
        playerView?.playbackController = playbackController
    
        self.playbackController.setVideos(videoArray as NSFastEnumeration?);
    }

Create the player view

  1. Create a function named createTVPlayerView as follows:

    • Lines 52-57: ensure that the storyboard bindings are set.
    • Lines 61-62: set the presenting view controller.
    • Lines 65-69: create the player view and add it as a subview of the main view.
    func createTVPlayerView() {
    
        // Make sure storyboard bindings are set up
        self.loadViewIfNeeded()
        if (videoContainerView == nil)
        {
            print("videoContainerView not bound to storyboard")
            return
        }
    
        // Set ourself as the presenting view controller
        // so that tab bar panels can present other view controllers
        let options = BCOVTVPlayerViewOptions()
        options.presentingViewController = self
    
        // Create and add to the video container view
        playerView = BCOVTVPlayerView(options: options)
        if (playerView != nil) {
            playerView!.frame = self.videoContainerView.bounds
            self.videoContainerView.addSubview(playerView!)
        }
    }

Set the delivery method for video sources

  1. Create a function that sets the delivery method for BCOVSources that belong to a video.

    func videoWithURL(url: NSURL) -> BCOVVideo {
        // set the delivery method for BCOVSources that belong to a video
        let source:BCOVSource = BCOVSource(url: url as URL?, deliveryMethod: kBCOVSourceDeliveryHLS, properties: nil)
        let video = BCOVVideo.init(source: source, cuePoints: BCOVCuePointCollection.init(array: []), properties: [NSObject:AnyObject]())
        return video!
    }

The rest

  1. Create functions to listen for the playback controller delegate methods, and functions for focus overrides.

    // MARK: Playback controller delegate methods
    
      func playbackController(_ controller: BCOVPlaybackController!, didAdvanceTo session: BCOVPlaybackSession!) {
          NSLog("ViewController Debug - Advanced to new session.")
      }
    
      func playbackController(_ controller: BCOVPlaybackController!, playbackSession session: BCOVPlaybackSession!, didReceive lifecycleEvent: BCOVPlaybackSessionLifecycleEvent!) {
          NSLog("Event: %@", lifecycleEvent.eventType)
      }
    
      // MARK: UIFocusEnvironment overrides
    
      // Focus Environment override for tvOS 9
      override var preferredFocusedView: UIView? {
          return playerView
      }
    
      // Focus Environment override for tvOS 10+
      override var preferredFocusEnvironments: [UIFocusEnvironment] {
          return (playerView != nil ? [ playerView! ] : [])
      }

View the code

The View Controller is now complete. Here is the full code:

//
//  ViewController.swift
//  Simple-Video-Playback
//
//  Copyright © 2018 Brightcove. All rights reserved.
//

import UIKit
import BrightcovePlayerSDK

let kViewControllerAccountID = "your account id" // for analytics

class ViewController: UIViewController, BCOVPlaybackControllerDelegate {
    @IBOutlet weak var videoContainerView: UIView!

    var playerView: BCOVTVPlayerView?

    let playbackController: BCOVPlaybackController = BCOVPlayerSDKManager.shared().createPlaybackController()

    required init?(coder aDecoder: NSCoder)
    {
        super.init(coder: aDecoder)

        playbackController.analytics.account = kViewControllerAccountID;
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.

        // create an array of videos
        var videoArray = [AnyObject]()
        videoArray = [videoWithURL(url: NSURL(string: "https://learning-services-media.brightcove.com/videos/hls/laughing_gull/laughing_gull.m3u8")!),
                      videoWithURL(url: NSURL(string: "https://learning-services-media.brightcove.com/videos/hls/greatblueheron/greatblueheron.m3u8")!)]

        createTVPlayerView()

        // Create and configure the playback controller
        playbackController.delegate = self
        playbackController.isAutoAdvance = true
        playbackController.isAutoPlay = true

        // Link the playback controller to the Player View
        playerView?.playbackController = playbackController

        self.playbackController.setVideos(videoArray as NSFastEnumeration?);
    }

    func createTVPlayerView() {

        // Make sure storyboard bindings are set up
        self.loadViewIfNeeded()
        if (videoContainerView == nil)
        {
            print("videoContainerView not bound to storyboard")
            return
        }

        // Set ourself as the presenting view controller
        // so that tab bar panels can present other view controllers
        let options = BCOVTVPlayerViewOptions()
        options.presentingViewController = self

        // Create and add to the video container view
        playerView = BCOVTVPlayerView(options: options)
        if (playerView != nil) {
            playerView!.frame = self.videoContainerView.bounds
            self.videoContainerView.addSubview(playerView!)
        }
    }

    func videoWithURL(url: NSURL) -> BCOVVideo {
        // set the delivery method for BCOVSources that belong to a video
        let source:BCOVSource = BCOVSource(url: url as URL?, deliveryMethod: kBCOVSourceDeliveryHLS, properties: nil)
        let video = BCOVVideo.init(source: source, cuePoints: BCOVCuePointCollection.init(array: []), properties: [NSObject:AnyObject]())
        return video!
    }

    // MARK: Playback controller delegate methods

    func playbackController(_ controller: BCOVPlaybackController!, didAdvanceTo session: BCOVPlaybackSession!) {
        NSLog("ViewController Debug - Advanced to new session.")
    }

    func playbackController(_ controller: BCOVPlaybackController!, playbackSession session: BCOVPlaybackSession!, didReceive lifecycleEvent: BCOVPlaybackSessionLifecycleEvent!) {
        NSLog("Event: %@", lifecycleEvent.eventType)
    }

    // MARK: UIFocusEnvironment overrides

    // Focus Environment override for tvOS 9
    override var preferredFocusedView: UIView? {
        return playerView
    }

    // Focus Environment override for tvOS 10+
    override var preferredFocusEnvironments: [UIFocusEnvironment] {
        return (playerView != nil ? [ playerView! ] : [])
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

Connect the storyboard view

Connect the Main.storyboard view with the videoContainer property.

  1. In the Xcode, open the Main.storyboard file.

  2. In the companion view, expand the View Controller Scene and then the View Controller menu to expose the View object.

    Storyboard view
    Storyboard view
  3. Show the Assistant Editor, and open the ViewController.swift file.

    Assistant editor
    Assistant editor
  4. Select the open circle next to the @IBOutlet for the videoContainerView, and drag it to the View object to connect these components.

    Connect the view
    Connect the view

Manage Media Security

App Transport Security (ATS) enforces secure connections between your app and web services. With Apple's release of the iOS 9 SDK, a new feature called App Transport Security (ATS) was added.

  1. One of the following situations will apply to your app:

    • By default the Brightcove Native SDK for iOS uses a source selection policy to choose HTTPS over HTTP sources, so you can build your apps with ATS enabled.

      That's it, you are ready to run your app.


    • If you are using HTTP sources or have other HTTP calls in your app, you may encounter the following error message:

      App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure.
      Temporary exceptions can be configured via your app's Info.plist file.

      This means that ATS is enabled, but your system is not configured to meet the ATS requirements. To fix this situation, see the Working with App Transport Security (ATS) document.

Run the app

The app is ready to build and run on an Apple TV or the Xcode Simulator. You should be able to play and navigate the specified video using the remote control.

Apple TV sample
Apple TV sample