Blog

How to check if a video ends playing in AVPlayer and other actions

In this tutorial, I’ll show you how to check if a video has ended, if a user canceled it, as well as how to turn the played video horizontally when the iOS app uses only the portrait mode. All this can be done with AVPlayerViewController.

What is the AVPlayerViewController?

The AVPlayerViewController is used to manage videos played in iOS apps. Similar to the UIViewController, it has methods that can be used for view customization. Unfortunately, Apple doesn’t provide easy methods for such common situations as:

  • Checking if the played video ended,
  • Checking the status of a played video
  • Checking if a user has canceled the video.

Let alone tracking the video progress. These pieces of information must be achieved in a different way. Stay with me if you want to learn them.

How to check if a video ended playing

If you want to check the status of a played video - one of the best solutions is to add an observer to the AVPlayer item. The AVPlayerViewController doesn’t notify about the ending of a video. This is why you need to check it by yourself.

You should add the NotificationCenter observer to your playVideo() method. Then - the method for handling information about ending of the played video.

Let’s say that your method looks like this:

let playerController = AVPlayerViewController()
var player: AVPlayer?

func playVideo(_ url: String) {
    if let videoUrl = URL(string: url) {
        player = AVPlayer(url: videoUrl)
        playerController.player = player
        self.present(playerController, animated: true) { self.playerController.player?.play() }

        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode.default, options: [])
        }
        catch {
            print("Setting category to AVAudioSessionCategoryPlayback failed.")
        }
    }
}

Inside the playVideo function you should add an observer that will check if the AVPlayer finished playing the video:

NotificationCenter.default.addObserver(self, selector: #selector(videoDidEnded), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player?.currentItem)

… As well as a function for handling this state:

@objc private func videoDidEnded() {
    //do something here
}

Method `videoDidEnded()` can be used for example for closing `AVPlayerViewController`. And don’t forget about removing the observer.

@objc private func videoDidEnded() {
    playerController.dismiss(animated: true, completion: nil)
    NotificationCenter.default.removeObserver(self)
}

How to check if a video was canceled?

OK, now we know how to recognize if a video ended. But how do we know whether a user canceled the playing process? Let’s use another observer. But in this case, I suggest adding an extension for Notification.Name. AVPlayerViewController has no default method to inform about a canceled video.

So let’s start with the extension:

extension Notification.Name {
    static let kAVPlayerViewControllerDismissingNotification = Notification.Name.init("dismissing")
}

Now we can add a method for observing if the played video was canceled. It will use the extension mentioned above:

private func observeWhenVideoIsBeingDismissed() {
    NotificationCenter.default.addObserver(self, selector: #selector(videoDidCancel), name: NSNotification.Name.kAVPlayerViewControllerDismissingNotification, object: nil)
}

And the handling method:

@objc private func videoDidCancel() {
    //do something when video is canceled
}

Same as in the previous method (`videoDidEnded()`), I also suggest removing the observer from `NotificationCenter`.

VPlayerViewController horizontally

The last method in this tutorial will let you play a video in AVPlayerViewController horizontally. This is useful when your app supports the portrait/upside-down mode only. If your project has the horizontal mode blocked, the AVPlayerViewController won’t let you show videos this way. To solve this problem, we will use AppDelegate. So in AppDelegate - or SceneDelegate - add this method:

func fetchCurrentVC(_ viewController: UIViewController?) -> UIViewController? {
    if let tabBarController = viewController as? UITabBarController {
        return fetchCurrentVC(tabBarController.selectedViewController)
    }
    if let navigationController = viewController as? UINavigationController{
        return fetchCurrentVC(navigationController.visibleViewController)
    }
    if let viewController = viewController?.presentedViewController {
        return fetchCurrentVC(viewController)
    }
    return viewController
}

If you don’t use UITabBarController or UINavigationController, simply remove the first statements. This function will return UIViewController which will be our AVPlayerViewController.

Then add this method:

func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
    if fetchCurrentVC(window?.rootViewController) is AVPlayerViewController {
        return .all
    }
    return [.portrait, .portraitUpsideDown]

This function changes supported orientation types - but only for presented AVPlayerViewController. As you can see, when AVPlayerViewController is shown, the app will support all face orientations. Otherwise, only portrait and portraitUpsideDown. That will let the user to watch the played video also in the horizontal mode.

Handling AVPlayerViewController actions: Wrapping up

I hope this tutorial will help you with your current projects that support AVPlayer.

Start a project with your dedicated software house

Top

Contact us

* Required fields

Elo Mordo!Elo Mordo!