Step-by-Step: Simple Video App using Swift

In this topic, you will learn how to build a simple video playback app using the Brightcove Player SDK for iOS. 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.

For this option, you will need a Policy Key. If you are not familiar with Policy Keys, see Policy API Overview.

Get started

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

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

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/VideoCloudBasicPlayer/swift sample app.
  3. Run the pod install command.
  4. Open and run the newly created workspace.

For details, see the Running Sample Apps for the Native SDK for iOS/tvOS document.

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 iOS project in Xcode. Select Create a new Xcode project.

    Create project
    Create project
  2. Select iOS and Single View Application for your new project. Select Next.

    Choose the project template
    Choose the 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.
    • Interface: Storyboard In this example, we are using the storyboard interface.
    • Language: Swift

    Click Next.

    Add project information
    Add project information
  4. Choose the location where you want to save your project and create it.

    Save project
    Save 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 1: Points to the GitHub location for the CocoaPods pod specs
    • Line 2: Points to the GitHub location for the Brightcove pod specs
    • Line 4: Defines the iOS platform version
    • Line 6: Sets Pods to use frameworks instead of static libraries
    • Lines 8-10: Install the Brightcove Native Player SDK

    source 'https://github.com/CocoaPods/Specs.git'
    source 'https://github.com/brightcove/BrightcoveSpecs.git'
    
    platform :ios, '16.0'
    
    use_frameworks!
    
    target 'Simple-Video-Playback' do
      pod 'Brightcove-Player-Core/XCFramework'
    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.

    If CocoaPods can not find a compatible version for the pod, or it is not the latest version, try running the following in the Terminal app:

    pod update

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

  5. The pod install command creates the .xcworkspace file for your project.

    Notice the last line, which is important — from this point on, you must do the following:

    • Open the Simple-Video-Playback.xcworkspace file in Xcode
    • Do not use the Simple-Video-Playback.xcodeproj file
    Workspace
    Workspace

Code the video app

Create the code for a simple video playback app.

  1. In Xcode, open the Simple-Video-Playback.xcworkspace file.

Set the audio behavior for the app

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

For this sample, we will use the playback category. This plays audio even when the screen is locked and with the Ring/Silent switch set to silent. Since we are playing video, we will use the moviePlayback mode. To keep it simple, we will put this code 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.

    • We need the code below in order to ensure that audio plays back when we expect it to. For example, without setting this code, we won't hear the video when the mute switch is on.

    //
    //  AppDelegate.swift
    //  Simple-Video-Playback
    //
    //  Copyright © 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(.playback, mode: .moviePlayback, options: .duckOthers)
      		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 invalidate graphics rendering callbacks. 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 catalog service.

  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 Objective-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.

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.

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

    • Line 12: Defines your Brightcove Playback API Policy Key
    • Line 13: Defines your Video Cloud Account ID
    • Line 14: Defines your Video Cloud Video ID

    // ** Customize these values with your own account information **
    let kViewControllerPlaybackServicePolicyKey = "your policy key"
    let kViewControllerAccountID = "your account id"
    let kViewControllerVideoID = "your video id"

Set the class delegate

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

  1. Update the View Controller class as follows:

    class ViewController: UIViewController, BCOVPlaybackControllerDelegate {
    

Declare constants and set the view

  1. In the ViewController class, add the following :

    • Line 16: Initializes a shared manager. The BCOVPlayerSDKManager class is a singleton that allows you to create other objects in the SDK ecosystem.
    • Line 17: Defines a constant, which initializes the Brightcove playback service with your Account ID and Policy Key. The BCOVPlaybackService class provides asynchronous methods for retrieving data from the Playback API.
    • Line 18: Defines a constant for the playback controller. The BCOVPlaybackController has methods to control playback functionality.
    • Line 19: Defines a variable for the view.

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

Create an init function

  1. Below the code in the previous step, create an init() function as follows:
    • Line 23: Uses the shared manager to create a playback controller.
    • Line 27: 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.

    • Lines 29-31: set the delegate and turn on the auto-advance and autoplay features.

     required init?(coder aDecoder: NSCoder) {
    	playbackController = (sharedSDKManager?.createPlaybackController())!
    
    	super.init(coder: aDecoder)
    
    	playbackController.analytics.account = kViewControllerAccountID // Optional
    
    	playbackController.delegate = self
    	playbackController.isAutoAdvance = true
    	playbackController.isAutoPlay = true
    }

Configure the player

  1. In the viewDidLoad() function, add the following:

    • Line 39: Create and set the Brightcove player controls, using the standard VOD layout.
    • Line 44: Adds the player view as a subview of the main view.
    • Line 45: Turn off auto-resizing mask.
    • Lines 46-51: Use Auto Layout to define dynamic contraints for the player view.
    • Line 54: Associate the player view with the playback controller.
    • Line 56: Calls the requestContentFromPlaybackService function, which we will define in the next step.

    override func viewDidLoad() {
      super.viewDidLoad()
      // Do any additional setup after loading the view, typically from a nib.
    
      // Set up our player view. Create with a standard VOD layout.
      guard let playerView = BCOVPUIPlayerView(playbackController: self.playbackController, options: nil, controlsView: BCOVPUIBasicControlView.withVODLayout()) else {
          return
      }
    
      // Install in the container view and match its size.
      self.videoContainerView.addSubview(playerView)
      playerView.translatesAutoresizingMaskIntoConstraints = false
      NSLayoutConstraint.activate([
          playerView.topAnchor.constraint(equalTo: self.videoContainerView.topAnchor),
          playerView.rightAnchor.constraint(equalTo: self.videoContainerView.rightAnchor),
          playerView.leftAnchor.constraint(equalTo: self.videoContainerView.leftAnchor),
          playerView.bottomAnchor.constraint(equalTo: self.videoContainerView.bottomAnchor)
      ])
    
      // Associate the playerView with the playback controller.
      playerView.playbackController = playbackController
    
      requestContentFromPlaybackService()
    }

Request content from the Brightcove library

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

  1. Below the viewDidLoad() function, create a function named requestContentFromPlaybackService() as follows:

    • Line 60: Returns a video object from the Playback API based on the given video id.
    • Line 63: Adds the video to the playback controller.
    • Line 65: Writes an error message if a playlist is not returned.

    func requestContentFromPlaybackService() {
      let configuration = [kBCOVPlaybackServiceConfigurationKeyAssetID:kViewControllerVideoID]
      playbackService?.findVideo(withConfiguration: configuration, queryParameters: nil, completion: { [weak self] (video: BCOVVideo?, jsonResponse: [AnyHashable: Any]?, error: Error?) in
          
          if let v = video {
              self?.playbackController.setVideos([v] as NSArray)
          } else {
              print("ViewController Debug - Error retrieving video: \(error?.localizedDescription ?? "unknown error")")
          }
      })
    }

View the code

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

//
//  ViewController.swift
//  VideoCloudBasicPlayer
//
//  Copyright © Brightcove, Inc. All rights reserved.
//

import UIKit
import BrightcovePlayerSDK

let kViewControllerPlaybackServicePolicyKey = "your policy key"
let kViewControllerAccountID = "your account id"
let kViewControllerVideoID = "your video id"

class ViewController: UIViewController, BCOVPlaybackControllerDelegate {

  let sharedSDKManager = BCOVPlayerSDKManager.shared()
  let playbackService = BCOVPlaybackService(accountId: kViewControllerAccountID, policyKey: kViewControllerPlaybackServicePolicyKey)
  let playbackController :BCOVPlaybackController
  @IBOutlet weak var videoContainerView: UIView!

  required init?(coder aDecoder: NSCoder) {
    playbackController = (sharedSDKManager?.createPlaybackController())!

    super.init(coder: aDecoder)

    playbackController.analytics.account = kViewControllerAccountID // Optional

    playbackController.delegate = self
    playbackController.isAutoAdvance = true
    playbackController.isAutoPlay = true
  }

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

    // Set up our player view. Create with a standard VOD layout.
    guard let playerView = BCOVPUIPlayerView(playbackController: self.playbackController, options: nil, controlsView: BCOVPUIBasicControlView.withVODLayout()) else {
        return
    }

    // Install in the container view and match its size.
    self.videoContainerView.addSubview(playerView)
    playerView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
      playerView.topAnchor.constraint(equalTo: self.videoContainerView.topAnchor),
      playerView.rightAnchor.constraint(equalTo: self.videoContainerView.rightAnchor),
      playerView.leftAnchor.constraint(equalTo: self.videoContainerView.leftAnchor),
      playerView.bottomAnchor.constraint(equalTo: self.videoContainerView.bottomAnchor)
    ])

    // Associate the playerView with the playback controller.
    playerView.playbackController = playbackController

    requestContentFromPlaybackService()
  }

  func requestContentFromPlaybackService() {
    let configuration = [kBCOVPlaybackServiceConfigurationKeyAssetID:kViewControllerVideoID]
    playbackService?.findVideo(withConfiguration: configuration, queryParameters: nil, completion: { [weak self] (video: BCOVVideo?, jsonResponse: [AnyHashable: Any]?, error: Error?) in
        
        if let v = video {
            self?.playbackController.setVideos([v] as NSArray)
        } else {
            print("ViewController Debug - Error retrieving video: \(error?.localizedDescription ?? "unknown error")")
        }
    })
  }
}

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

Set the value of your Account Id, which will be sent to Brightcove in a later step.

  1. Below the #import directives, add your own value for your Brightcove Account Id. This will be used to register your app with Brightcove.

    let kViewControllerAccountID = "your account id" // For Brightcove registration

Set the class delegates

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

  1. Update the View Controller class as follows:

    class ViewController: UIViewController, BCOVPlaybackControllerDelegate {

Declare constants and set the view

  1. In the ViewController class, add the following :

    • Line 14: Initializes a shared manager. The BCOVPlayerSDKManager class is a singleton that allows you to create other objects in the SDK ecosystem.
    • Line 15: Defines a constant for the playback controller. The BCOVPlaybackController has methods to control playback functionality.
    • Line 16: Defines a variable for the view.

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

Create an init function

  1. Below the code in the previous step, create an init() function as follows:
    • Line 20: Uses the shared manager to create a playback controller.
    • Line 25: Sends your Video Cloud Publisher ID to Brightcove analytics to register your app.

    • Lines 28-30: Set the delegate and turns on the auto-advance and autoplay features.

    required init?(coder aDecoder: NSCoder) {
      // Create the Brightcove playback controller
      playbackController = (sharedSDKManager?.createPlaybackController())!
    
      super.init(coder: aDecoder)
    
      // Register your app with Brightcove
      playbackController.analytics.account = kViewControllerAccountID
    
      // Configure the player
      playbackController.delegate = self
      playbackController.isAutoAdvance = true
      playbackController.isAutoPlay = true
    }

Configure the player

  1. In the viewDidLoad() function, add the following:

    • Lines 38-40: Create an array of video sources using url paths.
    • Lines 43-45: Configures the playback controller's view.
    • Line 48: Adds the player view as a subview of the main view.
    • Line 49: Turn off auto-resizing mask.
    • Lines 50-55: Use Auto Layout to define dynamic contraints for the player view.
    • Line 58: Associates the player view with the playback controller.
    • Line 61: Adds the video array to the controller's playback queue.
    • Line 62: Starts playback of the first video.

    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://solutions.brightcove.com/bcls/assets/videos/Great_Horned_Owl.mp4")!),
                    videoWithURL(url: NSURL(string: "https://solutions.brightcove.com/bcls/assets/videos/Great_Blue_Heron.mp4")!)]
    
      // Set up the player view with a standard VOD layout.
      guard let playerView = BCOVPUIPlayerView(playbackController: self.playbackController, options: nil, controlsView: BCOVPUIBasicControlView.withVODLayout()) else {
          return
      }
    
      // Install the container view and match its size.
      self.videoContainerView.addSubview(playerView)
      playerView.translatesAutoresizingMaskIntoConstraints = false
      NSLayoutConstraint.activate([
          playerView.topAnchor.constraint(equalTo: self.videoContainerView.topAnchor),
          playerView.rightAnchor.constraint(equalTo: self.videoContainerView.rightAnchor),
          playerView.leftAnchor.constraint(equalTo: self.videoContainerView.leftAnchor),
          playerView.bottomAnchor.constraint(equalTo: self.videoContainerView.bottomAnchor)
      ])
    
      // Associate the playerView with the playback controller.
      playerView.playbackController = playbackController
    
      // Load the video array into the player and start video playback
      playbackController.setVideos(videoArray as NSArray)
      playbackController.play();
    }

Set the delivery method for video sources

  1. Below the viewDidLoad() function, 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!
    }

View the code

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

//
//  ViewController.swift
//  Simple-Video-Playback for Brightcove Player Customers
//
//  Copyright © Brightcove. All rights reserved.
//

import UIKit
import BrightcovePlayerSDK

let kViewControllerAccountID = "your account id" // For Brightcove registration

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

    required init?(coder aDecoder: NSCoder) {
        // Create the Brightcove playback controller
        playbackController = (sharedSDKManager?.createPlaybackController())!

        super.init(coder: aDecoder)

        // Register your app with Brightcove
        playbackController.analytics.account = kViewControllerAccountID

        // Configure the player
        playbackController.delegate = self
        playbackController.isAutoAdvance = true
        playbackController.isAutoPlay = true
    }

    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://solutions.brightcove.com/bcls/assets/videos/Great_Horned_Owl.mp4")!),
                      videoWithURL(url: NSURL(string: "https://solutions.brightcove.com/bcls/assets/videos/Great_Blue_Heron.mp4")!)]

        // Set up the player view with a standard VOD layout.
        guard let playerView = BCOVPUIPlayerView(playbackController: self.playbackController, options: nil, controlsView: BCOVPUIBasicControlView.withVODLayout()) else {
            return
        }

        // Install in the container view and match its size.
        self.videoContainerView.addSubview(playerView)
        playerView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            playerView.topAnchor.constraint(equalTo: self.videoContainerView.topAnchor),
            playerView.rightAnchor.constraint(equalTo: self.videoContainerView.rightAnchor),
            playerView.leftAnchor.constraint(equalTo: self.videoContainerView.leftAnchor),
            playerView.bottomAnchor.constraint(equalTo: self.videoContainerView.bottomAnchor)
        ])

        // Associate the playerView with the playback controller.
        playerView.playbackController = playbackController

        // Load the video array into the player and start video playback
        playbackController.setVideos(videoArray as NSArray)
        playbackController.play();
    }

    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!
    }
}

Connect the storyboard view

Connect the Main.storyboard view with the videoContainerView 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. Click Add Editor on Right, and open the ViewController.swift file.

    Add editor
    Add editor
  4. Select the open circle next to the @IBOutlet for 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 your remote assets use HTTPS instead of HTTP sources, then 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 iPhone, iPad or the iOS Simulator. You should be able to play the videos from your playlist.

iPhone sample
iPhone sample

The app is ready to build and run on an iPhone, iPad or the iOS Simulator. You should be able to play the videos defined in your array.

iPhone sample
iPhone sample