Migration Guide - v2 to v3 (iOS SDK)


The following points will explain all breaking changes, renamed methods and configuration objects, as well as minimum requirements that need to be fullfilled to migrate and benefit from all the major performance and usability improvements that become available with v3.

V3 of the iOS/tvOS Player SDK marks a new direction where the player itself and the sources it plays back become more decoupled. This allows for sources to have their own lifecycle, emit their own events and offer functionality even when the source is currently not being played back. For more details on how the top-level components fit together in V3, refer to the Player, Source and PlaylistApi documentation.

With this new direction comes the ability to load multiple sources into the player via a PlaylistConfig. The player will play back one source after another until it reaches the end of the playlist. Sources in the playlist can already preload content before they are being played back, leading to gapless playback across sources without the overhead of unloading and loading a new source like in V2.

Minimum Requirements

Package manager:
v3 SDK will be delivered as pre-compiled XCFramework through

Supported iOS/tvOS Platforms (Deployment Target):

  • iOS 14 or higher
  • tvOS 14 or higher

Google Cast:

  • CAF compatible v3 receiver applications required

Bitmovin Player UI:

  • v3.25.x or higher (default and custom versions)


  • The initial 3.0.0 version does not support loading live-streams inside a playlist.
    As we can't detect the type until we actually start loading the source there won't be an error when loading a live-stream. Doing so will result in unexpected behavior.

  • The event transition towards SourceEvents isn't finished yet.
    More events will be migrated to SourceEvents and emitted on a per-source basis over the next releases. If you plan on directly using the types PlayerEvent and SourceEvent anywhere, be aware that there could be API breaking change in the future when changing the super-type of event classes. Learn More


This table lists all naming changes from v2 to v3 with its replacements.

Player.sourceMetadataWas moved to Source.metadata
Boolean properties could be accessed without a proper prefix (e.g. .isPlaying was accessible via .playing from ObjC)All Boolean properties now have a proper prefix
BMP prefix when using type/enum from SwiftNo more BMP prefixes for types/enums used from Swift


This table lists API which was removed in v3 with its replacements (if any).

Player.preloadremoved without replacement as this was never implemented properly
Player.streamTypeis now represented through SourceConfig.type
OfflineContentManager.download(minimumBitrate:)The minimumBitrate can now be set only via the DownloadConfig
Player.setupremoved without replacement (Details)
ConfigurationUpdatedEventremoved as a configuration can't be updated anymore
PlayerConfiguration.sourceConfigurationreplaced with new loading workflows (Details)
Jsonableremoved without replacement as we no longer support loading a web-based PlayerConfig

Player setup

We no longer expose the concrete implementation for the Player. Therefore You can no longer create a direct instance from the Player. From now on the only way to create a player instance is using the PlayerFactory:


let player = Player(configuration: configuration)
// or
let player = Player() // when no PlayerConfig is needed


let player = PlayerFactory.createPlayer(playerConfig: playerConfig)
// or
let player = PlayerFactory.createPlayer() // when no PlayerConfig is needed

Loading a Source


The SourceItem was replaced by SourceConfig and the old SourceConfiguration was removed completely. SourceConfig from now on refers to the old SourceItem.

As our SourceConfig was based on the SourceConfig from the web-player there was the possibility to set up multiple configurations for each streaming technology (HLS, Dash ...). We want to detach from this concept starting with v3. Therefore we deprecated all the legacy types which were used to set up those different sources:

  • MediaSource
    • AdaptiveSource
      • HLSSource
      • DashSource
    • ProgressiveSource

The new designated way to create a SourceConfig is to use the URL and the type directly on the SourceConfig initializer:


let sourceConfig = SourceConfig(hlsSource: HLSSource(url: streamUrl))


let sourceConfig = SourceConfig(url: streamUrl, type: .HLS)


The Source is, next to the Player, the new main component in the SDK. See the documentation for more detailed insights.

To create an instance of a Source a SourceConfig is needed. The SourceConfig can then be passed to the SourceFactory to create a Source instance.

let source = SourceFactory.createSource(from: sourceConfig)

To load a Source into the Player we created a new load method that accepts a Source:

player.load(source: source)

If you don't need to handle Sources explicitly you can still load a SourceConfig directly:

// v3
player.load(sourceConfig: sourceConfig)

Event handling

Each Source can have its own listeners by now. To enable that we split the existing PlayerEvents into PlayerEvent and SourceEvent.


class PlayerEvent: NSObject { ... }
class SourceLoadedEvent: PlayerEvent { ... }


protocol Event: NSObject { ... }
protocol SourceEvent: Event { ... }
class SourceLoadedEvent: SourceEvent { ... }

We introduce the new Event protocol as the root type for all events. Each SourceEvent (e.g. SourceLoadedEvent) implements the SourceEvent protocol and each PlayerEvent (e.g. PlayEvent) extends the PlayerEvent super class.

Events which are already SourceEvents:

  • DurationChangedEvent
  • SourceLoadEvent
  • SourceLoadedEvent
  • SourceUnloadEvent
  • SourceUnloadedEvent
  • SourceWarningEvent
  • SourceErrorEvent

Every SourceEvent emitted from the currently active Source will be also emitted through the Player.
This means that SourceEvents will be received for the according Source instance or directly via the Player for the currently active Source.

extension PlaybackViewController: PlayerListener {
    // Receive the DurationChangedEvent through the player only for the active source
    func onDurationChanged(_ event: DurationChangedEvent, player: Player) {
        // ...

extension PlaybackViewController: SourceListener {
    // Receive the DurationChangedEvent on the source emitting the event (even if the source is not active)
    func onDurationChanged(_ event: DurationChangedEvent, source: Source) {
        // ...

Source Listener

If you want to listen to SourceEvent and receive them on the actual source (also for non-active Sources) you can attach a SourceListener to a Source:

// v3
source.add(listener: sourceListener)


To distinguish which source emitted an event we added the sender to the SourceListener methods. To have a unified API we decided to also add this to the PlayerListener and to the UserInterfaceListener:


func onPlay(_ event: PlayEvent) {
    // If the same listener handles multiple player instances there is no way to detect which player emitted the event


func onPlay(_ event: PlayEvent, player: Player) {
    // The player instance which is associated with the emitted event

func onSourceLoaded(_ event: SourceLoadedEvent, source: Source) {
    // The source instance which is associated with the emitted event


The DurationChangedEvent is no longer emitted initially when the duration is available the first time. As replacement access the duration when the SourceLoadedEvent is received.

SourceLoad related events

As the SourceLoaded and the SourceUnloaded events will now be emitted per source (and also for non-active sources), we needed to add replacements to ensure old workflows still work as expected.

SourceLoadedEvent was emitted when we were about to load a source indicating the player started a source life-cyclePlayerActiveEvent is emitted when the player received one or more sources and is about to start loading
SourceUnloadedEvent was emitted after we finished unloading a source indicating the player finished the source life-cyclePlayerInactiveEvent is emitted when all sources were removed from the player and as no more sources attached

UI / View

Default Bitmovin Player Web UI

The new v3 iOS SDK isn’t compatible with Bitmovin Player Web UI v2.x. To use the v3 SDK with a customized Bitmovin Player Web UI you will need to update your Player Web UI version to v3.x. The recommended version is 3.25.0 and above.

We continue to support Bitmovin Player Web UI v2.x for use with our v2 iOS SDK only. More details on the Bitmovin Player Web UI can be found here.


To create a custom UI you no longer need to sub-class PlayerView, you can just subclass UIView by now. The PlayerView should only be used if you want to use any of the UIs we provide.

We added new methods on the Player protocol to allow registering an AVPlayerLayer or an AVPlayerViewController to give more flexibility about where the video should be rendered.


class CustomView: PlayerView {
    override init(player: Player, frame: CGRect) {
        super.init(player: player, frame: frame)

Using AVPlayerLayer.

class CustomView: UIView {
    init(player: Player, frame: CGRect) {
        super.init(frame: frame)


    var playerLayer: AVPlayerLayer {
        layer as! AVPlayerLayer

    override class var layerClass: AnyClass {

Using AVPlayerViewController.

let avPlayerViewController = AVPlayerViewController()


We have updated our iOS Samples GH Repository as well to get you started with our new major version 3 for iOS/tvOS. Check them out!