Fullscreen Implementation Guide
Why native fullscreen prevents StreamLayer formats and how to implement app-managed fullscreen for full SDK functionality.
The StreamLayer SDK renders interactive units and ad formats alongside your video player — including sidebar, L-bar, picture-in-picture (PIP), side-by-side, and frame ad layouts. These formats require the host app to control the video player's size and position through Auto Layout constraints. When a host app uses the native AVPlayerViewController fullscreen mode, the system takes over the display and the host app loses this control.
This guide explains the issue and walks through the recommended approach: app-managed fullscreen.
The Problem: Native Fullscreen
iOS provides built-in fullscreen playback through AVPlayerViewController. When fullscreen is activated, the system presents the player in its own window or transitions to a full-screen presentation, taking control away from the host app's view hierarchy.
This creates two issues for StreamLayer integration:
1. Video resizing is blocked. Formats like L-bar, sidebar, PIP, side-by-side, and frame ad work by resizing and repositioning the video player to make room for the StreamLayer Element. In native fullscreen, AVPlayerViewController owns the layout — the host app cannot update constraints on the video view.
2. View hierarchy access is limited. While AVPlayerViewController provides a contentOverlayView for adding views on top of video, this only supports the basic overlay format. It does not support layouts where the video needs to shrink, move, or share the screen with the StreamLayer Element.
If your app only uses the overlay format (a semi-transparent layer on top of full-screen video), native fullscreen will work. But if you use any other format, you need app-managed fullscreen.
The Solution: App-Managed Fullscreen
Instead of calling AVPlayerViewController's native fullscreen, create a fullscreen experience that your app controls. This means expanding a container view to fill the entire screen while keeping the video player and StreamLayer Element as child views that you can resize via Auto Layout.
Step 1: Use AVPlayerLayer Instead of AVPlayerViewController
Use AVPlayerLayer embedded in a UIView rather than AVPlayerViewController. This gives you full control over the player's frame and constraints.
// Use AVPlayerLayer for full layout control
class PlayerContainerView: UIView {
override class var layerClass: AnyClass { AVPlayerLayer.self }
var playerLayer: AVPlayerLayer { layer as! AVPlayerLayer }
func configure(with player: AVPlayer) {
playerLayer.player = player
playerLayer.videoGravity = .resizeAspect
}
}Step 2: Build Your Own Fullscreen Toggle
Create a container view that holds both the video player and the StreamLayer Element. Toggle fullscreen by expanding this container to fill the screen.
class VideoHostViewController: UIViewController {
private let containerView = UIView()
private let playerView = PlayerContainerView()
private var isFullScreen = false
// Constraints that change between windowed and fullscreen
private var windowedConstraints: [NSLayoutConstraint] = []
private var fullScreenConstraints: [NSLayoutConstraint] = []
func toggleFullScreen() {
isFullScreen.toggle()
if isFullScreen {
// Hide status bar
setNeedsStatusBarAppearanceUpdate()
// Expand container to fill the screen
NSLayoutConstraint.deactivate(windowedConstraints)
NSLayoutConstraint.activate(fullScreenConstraints)
} else {
// Restore windowed layout
NSLayoutConstraint.deactivate(fullScreenConstraints)
NSLayoutConstraint.activate(windowedConstraints)
setNeedsStatusBarAppearanceUpdate()
}
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
override var prefersStatusBarHidden: Bool { isFullScreen }
}Step 3: Let StreamLayer Resize the Video
With app-managed fullscreen, the SDK's SLRLBarDelegate and SLRSideBarDelegate methods work as expected because your app controls the constraints. When the SDK requests a layout change (for example, shrinking the video to make room for a sidebar), your delegate methods update the constraints on your playerView.
// MARK: - SLRLBarDelegate
func moveRightSide(for points: CGFloat) {
playerView.snp.updateConstraints {
$0.right.equalToSuperview().offset(-points)
}
}
func moveBottomSide(for points: CGFloat) {
guard SLRStateMachine.orientation != .vertical else { return }
playerView.snp.updateConstraints {
$0.bottom.equalToSuperview().offset(-points)
}
}See the Constraints Guide for the full delegate implementation.
Step 4: Disable Native Fullscreen Controls
If you use AVPlayerViewController elsewhere in your app, make sure the native fullscreen button does not appear when the StreamLayer SDK is active.
// If using AVPlayerViewController for non-StreamLayer screens,
// disable fullscreen when StreamLayer is integrated
playerViewController.entersFullScreenWhenPlaybackBegins = false
playerViewController.allowsPictureInPicturePlayback = falseQuick Reference: What Works in Each Mode
| Format | Native Fullscreen | App-Managed Fullscreen |
|---|---|---|
| Overlay (semi-transparent) | Yes | Yes |
| Sidebar | No | Yes |
| L-Bar | No | Yes |
| PIP (picture-in-picture) | No | Yes |
| Side-by-Side | No | Yes |
| Frame Ad | No | Yes |
Common Mistakes
Using AVPlayerViewController for fullscreen. This is the most common cause of "the SDK only shows overlays, not sidebars." Switch to AVPlayerLayer in a custom UIView so your app controls the layout.
Forgetting to hide the status bar. In app-managed fullscreen, you need to handle status bar visibility yourself via prefersStatusBarHidden. Native fullscreen does this automatically.
Not forwarding orientation changes. Make sure your fullscreen container responds to device orientation changes and updates the StreamLayer Element constraints accordingly. The SDK needs accurate frame information to render correctly.
Related
- Integration Guide — Full SDK setup including format configuration
- Constraints Guide — Detailed Auto Layout and L-Bar delegate implementation
- Layout Guide — Android equivalent of this guide (Android does not have this limitation but has similar layout patterns)
Updated 15 days ago
