let videoPlayer = AVPlayer(URL: url)
NotificationCenter.default.addObserver(self, selector:#selector(self.playerDidFinishPlaying(note:)),name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: player.currentItem)
func playerDidFinishPlaying(note: NSNotification){
//Called when player finished playing
}
Here 'fullUrl' is the URL of the video and make sure that there would be no space in the URL, You should replace 'Space' with '%20' so that URL will work file.
let videoURL = NSURL(string: fullUrl)
let player = AVPlayer(url: videoURL! as URL)
playerViewController.delegate = self
playerViewController.player = player
self.present(playerViewController, animated: false) {
self.playerViewController.player!.play()
NotificationCenter.default.addObserver(self, selector: #selector(yourViewControllerName.playerDidFinishPlaying), name: Notification.Name.AVPlayerItemDidPlayToEndTime, object: self.player?.currentItem)
}
Add this below given method in your view controller.
func playerDidFinishPlaying(){
print("Video Finished playing in style")
}
I know there are a lot of accepted answers here...
But, another route might be to add a boundary time observer to your AVPlayer. You would have to have the duration of the video, which you can get from your player.currentItem, and then add it as your desired time boundary.
fileprivate var videoEndObserver: Any?
func addVideoEndObserver() {
guard let player = YOUR_VIDEO_PLAYER else { return }
// This is just in case you are loading a video from a URL.
guard let duration = player.currentItem?.duration, duration.value != 0 else {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5, execute: { [weak self] in
self?.addVideoEndObserver()
})
return
}
let endTime = NSValue(time: duration - CMTimeMakeWithSeconds(0.1, duration.timescale))
videoEndObserver = player.addBoundaryTimeObserver(forTimes: [endTime], queue: .main, using: {
self.removeVideoEndObserver()
// DO YOUR STUFF HERE...
})
}
func removeVideoEndObserver() {
guard let observer = videoEndObserver else { return }
videoPlayer.player?.removeTimeObserver(observer)
videoEndObserver = nil
}
Using Combine, and also making sure the notification comes from the AVPlayerItem you are interested in and not just any. I am playing multiple items at once, so this would work in that scenario as well.
private var subscriptions: Set<AnyCancellable> = []
NotificationCenter.default.publisher(for: .AVPlayerItemDidPlayToEndTime, object: player.currentItem)
.receive(on: RunLoop.main)
.sink { [weak self] notification in
guard let item = notification.object as? AVPlayerItem else { return }
if item == self?.player.currentItem {
//.... Here you know it was the item you are interested in that played to end and not just any
}
}
.store(in: &subscriptions)
I had an issue with the Notification never getting called, setting the notification inside the presentation of the AVPlayerViewController solved it for me:
func presentVideo(url:URL) {
let player = AVPlayer(url: url)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
DispatchQueue.main.async {
playerViewController.player!.play()
//NOTE: The notification must be created here for it to work as expected
NotificationCenter.default.addObserver(self, selector: #selector(self.videoDidEnd), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: nil)
}
}
}