---
updatedAt: 2026-06-03T20:22:00.000Z
agentTools:
  siteIndex: https://developer.bitmovin.com/llms.txt
  projectIndex: https://developer.bitmovin.com/playback/llms.txt
---

# Picture-in-Picture without using the Bitmovin Web UI

This tutorial will guide you through enabling Picture-in-Picture mode on iOS when using a Custom Native UI instead of the Bitmovin Web UI.

## Overview

Bitmovin introduced the ability to configure Picture-in-Picture mode within our Bitmovin Player as part of our V3 SDK. However, since enabling Picture-in-Picture requires listening to a AVKit level Delegate, the BitmovinPlayer is only able to support Picture-in-Picture within our own [HTML-based Player UI](https://github.com/bitmovin/bitmovin-player-ui). Luckily though, there is a very simple way to utilize that same `AVPictureInPictureControllerDelegate` if you instead prefer to create and use your own custom Native UI for iOS.

To implement Picture-in-Picture within a Native UI, the overall process is pretty simple actually and consists of using iOS' AVKit protocol [AVPictureInPictureControllerDelegate](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate) along with just a couple of it’s built-in methods to control Picture-in-Picture

## Player Configuration

When using your Native UI, the first thing you will want to do is to let the Bitmovin Player know that you do not want to use the Bitmovin UI within the [StyleConfig](https://cdn.bitmovin.com/player/ios/3/docs/Classes/StyleConfig.html).

```swift
let config = PlayerConfig()
config.styleConfig.isUiEnabled = false
```

Optionally, if you also want PiP to work with Background Playback mode, you will need to enable BackgroundPlayback in the Bitmovin [PlaybackConfig](https://cdn.bitmovin.com/player/ios/3/docs/Classes/PlaybackConfig.html):

```swift
config.playbackConfig.isBackgroundPlaybackEnabled = true
```

> ⚠️ Use a single Picture-in-Picture owner for a playback session
>
> The custom native PiP approach shown here uses an `AVPictureInPictureController` created from the player layer. Do not combine this with an app-owned `AVPlayerViewController` that also has built-in Picture-in-Picture enabled.
>
> Mixed PiP ownership can lead to lifecycle issues, such as playback pausing during backgrounding or PiP restoration. If you use `AVPlayerViewController`, use its built-in PiP as the PiP owner instead of creating a separate `AVPictureInPictureController`.

## Native UI Class

When creating a Native Swift-based UI it is important that this class inherits from the following 2 classes/protocols

`PlayerView` - The core Bitmovin Player View class that holds the Player instance.

`AVPictureInPictureControllerDelegate` - Protocol that will allow your UI to handle Picture-in-Picture events.

```swift
import Foundation
import BitmovinPlayer
class CustomPiPView: PlayerView, AVPictureInPictureControllerDelegate {
  
}
```

In our newly created `CustomPipView` class we can now initialize the PlayerView and then initialize the `AvPictureInPictureController` to a stored variable like so:

```swift
var controller: AVPictureInPictureController?

override init(player: Player, frame: CGRect) {
    super.init(player: player, frame: frame)
    let layer = self.layer as! AVPlayerLayer
    if AVPictureInPictureController.isPictureInPictureSupported() {
        self.controller = AVPictureInPictureController(playerLayer: layer)
        self.controller?.delegate = self
    }
}
```

Finally we can create two methods for entering and exiting Picture-in-Picture using the `AvPictureInPictureController`’s built-in methods `startPictureInPicture` and `stopPictureInPicture`.

```swift
func enterPiP() {
    self.controller?.startPictureInPicture()
}

func exitPiP() {
    self.controller?.stopPictureInPicture()
}
```

There are also some additional available Picture-in-Picture event listeners and additional capabilities(i.e. state callers, image customizations, etc.) which can found in the `AvPictureInPictureController`’s docs here → [Apple Developer Documentation](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate).

#### Full Example Class:

```swift
import Foundation
import BitmovinPlayer

class CustomPiPView: PlayerView, AVPictureInPictureControllerDelegate {
    var controller: AVPictureInPictureController?
	
    override init(player: Player, frame: CGRect) {
        super.init(player: player, frame: frame)
        let layer = self.layer as! AVPlayerLayer
        if AVPictureInPictureController.isPictureInPictureSupported() {
            self.controller = AVPictureInPictureController(playerLayer: layer)
            self.controller?.delegate = self
        }
    }

    func enterPiP() {
        self.controller?.startPictureInPicture()
    }

    func exitPiP() {
        self.controller?.stopPictureInPicture()
    }
}

```

## Using The Native UI

Now that our Player is configured and our Native UI class is configured for Picture-in-Picture functionality we can create an instance of this Native UI to be used with the Bitmovin Player form our ViewController:

```swift
// class level variables:
var playerView: CustomPiPView!

// override the view loaded function
override func viewDidLoad() {
    self.playerView = createPlayerView(player: player)
}

private func createPlayerView(player: Player) -> CustomPiPView {
    let playerView = CustomPiPView(player: player, frame: .zero)
    playerView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
    playerView.frame = view.bounds
    return playerView
}

```

<br />