iOS AVPlayerViewController distinguish user actions to exit Picture-in-Picture mode

190 views Asked by At

In my iOS Video Player, when in the Picture-in-Picture mode (PIP), how can I handle specific user actions like close or restore. The existing delegate provides a way to know when PIP mode is stopped but I wan't different behavior to be executed on different user actions:

  • close - let the controller go and keep it closed
  • restore - re-present the player and continue playback

enter image description here

After implementing AVPlayerViewControllerDelegate, AVPlayerViewController calls the following functions regardless of what button user tapped:

playerViewControllerWillStopPictureInPicture
playerViewControllerDidStopPictureInPicture

I also defined method restoreUserInterfaceForPictureInPictureStopWithCompletionHandler but it seems not getting called for some reason on exit from the PIP mode.

    func restoreUserInterfaceForFullScreenExit(completionHandler: @escaping (Bool) -> Void) {
        completionHandler(true)
    }
    
    func restoreUserInterfaceForPictureInPictureStop(completionHandler: @escaping (Bool) -> Void) {
        completionHandler(true)
    }
2

There are 2 answers

1
Yulia On BEST ANSWER

In general I have view that contained AVPLayer playerView and it has delegate:

var pipControllerDelegate: AVPictureInPictureControllerDelegate?
playerView.pipControllerDelegate = self

I've implemented required methods by the following way and it works for me:

extension PlayerView: AVPictureInPictureControllerDelegate {
func pictureInPictureControllerDidStopPictureInPicture(_ pictureInPictureController: AVPictureInPictureController) {
    close()
}

func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController,
                                  restoreUserInterfaceForPictureInPictureStopWithCompletionHandler completionHandler: @escaping (Bool) -> Void) {
        let isPipPlaying = (pictureInPictureController.playerLayer.player?.timeControlStatus == .playing)
        if isPipPlaying {
            play()
        } else {
            paused()
        }
        completionHandler(true)
}

May be your delegate bacomes nil at some place of code?

1
Yulia On

To restore your player and continue playing you should use playerViewController(_:restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:) method of AVPictureInPictureControllerDelegate.

This method is called before playerViewControllerWillStopPictureInPicture(_:) and playerViewControllerDidStopPictureInPicture(_:) as it is described in Apple documentation.