Quantcast
Channel: swift – Tiago Lopes
Viewing all articles
Browse latest Browse all 9

Picture in Picture Cheat Sheet (iOS)

$
0
0

TL;DR

Here you can find a simple PiP implementation. Clone and run it, and then check the following components:

  1. PictureInPicture.swift (component that encapsulates the AVPictureInPictureController)
  2. MovieView.swift (contains the pip button, with calls to start or stop PiP)
  3. MoviesCatalogView.swift (contains the PiP restoration logic)

What it is

When users watch videos, PiP allows them to continue playback while navigating in other areas of the application or iOS itself. It does so by “moving” the playback to a floating window controlled by the OS.

Picture in Picture in action

Initialization

To control pip, one must interface with AVPictureInPictureController, a class belonging to the AVKit framework. Initialization usually happens in this order:

  1. You’ll need an AVPlayer instance
  2. Create an AVPlayerLayer configured with your player instance
  3. Check if the current device supports pip: AVPictureInPictureController.isPictureInPictureSupported()
  4. Create an instance of the pip controller: AVPictureInPictureController(playerLayer: yourLayer)
  5. Check if the controller can start pip (this step is asynchronous) using controller.publisher(for: \.isPictureInPicturePossible)
import AVKit

// ...

guard AVPictureInPictureController.isPictureInPictureSupported() else {
    return
}

let pipController = AVPictureInPictureController(playerLayer: myLayer)
pipController.delegate = self

pipController
    .publisher(for: \.isPictureInPicturePossible)
    .sink { ... }
    .store(in: ...)

Start/stop

pipController.startPictureInPicture()
pipController.stopPictureInPicture()

It’s possible to automatically start it as soon as the app enters background:

pipController.canStartPictureInPictureAutomaticallyFromInline = true

Reacting to pip state

Pip uses the classical delegation mechanism to inform when its state changes, as well as if it couldn’t launch because of an error:

pipController.delegate = yourConformingInstance
// ...
extension SomeComponent: AVPictureInPictureControllerDelegate {
        func pictureInPictureControllerDidStartPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        // TODO: deal with any changes to state
    }
    
    func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
        // TODO: deal with any changes to state
    }
    
    func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, failedToStartPictureInPictureWithError error: Error) {
        // TODO: deal with any errors
    }
}

Restoring playback UI

Users might return to the original playback context in your app. The delegate has a specific method for that, in two flavors:

Closure based approach

func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
    // TODO: Restore your UI
    // Invoke the closure with a flag indicating if the UI could be restored or not
}

Async function

func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController) async -> Bool {
    // TODO: await for UI restoration
    // TODO: Return flag indicating if UI was restored or not
}

Notes:

  1. When restoring your UI, make sure the frame of your player view stays consistent and doesn’t change, otherwise PIP animation will get buggy and animate to the wrong position.
  2. Playback restoration will require some effort depending on how your app is architected and what stack it uses (SwiftUI vs. UIKit, for example). For a simple example on how this could be accomplished, check this implementation repository.

Limitations

  1. Lack of customization in the controls (we can’t change how they look)
  2. We can hide specific controls using the requiresLinearPlayback property of the pipController
  3. This repository contains some ways of changing it (bear in mind some of these approaches are not documented by Apple)
  4. Finally, only iPad simulators support PiP

Viewing all articles
Browse latest Browse all 9

Latest Images

Trending Articles





Latest Images