This question already has answers here:
Done button click event in AVPlayerViewController
(9 answers)
Closed 3 years ago.
There is one functionality of Video playing Like linkedIn video playing.
i am using AVPlayerViewController for playing video.in that i am facing issue that i am not able to detect Close button event when AVPlayerviewController will close.
is there any Observer or method which will call when AVPlayerController will dismiss?
Swift 3.2
import UIKit
import AVKit
import AVFoundation
class PlayResourcesVC: UIViewController {
//MARK:- Variable Declarations
var video_Url:String = String()
let playerController = AVPlayerViewController()
//MARK:- ViewDidload
override func viewDidLoad() {
super.viewDidLoad()
let player = AVPlayer(url: URL(string: video_Url)!)
playerController.player = player
self.present(playerController, animated: false) {
player.play()
self.playerController.addObserver(self, forKeyPath: #keyPath(UIViewController.view.frame), options: [.old, .new], context: nil)
}
}
override func viewDidDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(NSNotification.Name.AVPlayerItemDidPlayToEndTime)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
//MARK:- All Method
func playerDidFinishPlaying(note: NSNotification) {
self.navigationController?.popViewController(animated: false)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
self.playerController.removeObserver(self, forKeyPath: #keyPath(UIViewController.view.frame))
self.navigationController?.popViewController(animated: false)
}
}
Related
Is there any method to identify when we close the AVPlayerViewController when the video is still playing?
Attached the image as to which 'Close' button I am referring to.
try this :-
import UIKit
import AVKit
import AVFoundation
class VC: UIViewController {
var video_Url:String = String()
let playerController = AVPlayerViewController()
//MARK:- ViewDidload
override func viewDidLoad() {
super.viewDidLoad()
let player = AVPlayer(url: URL(string: video_Url)!)
playerController.player = player
self.present(playerController, animated: false) {
player.play()
self.playerController.addObserver(self, forKeyPath: #keyPath(UIViewController.view.frame), options: [.old, .new], context: nil)
}
}
override func viewDidDisappear(_ animated: Bool) {
NotificationCenter.default.removeObserver(NSNotification.Name.AVPlayerItemDidPlayToEndTime)
}
//MARK:- All Method
func playerDidFinishPlaying(note: NSNotification) {
self.navigationController?.popViewController(animated: false)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
self.playerController.removeObserver(self, forKeyPath: #keyPath(UIViewController.view.frame))
self.navigationController?.popViewController(animated: false)
}
}
I have an initial screen with a button on it which when you press it a video plays. Then once the film has ended I want the video to close and it to go to a different screen. At the moment I am able to make the button play the video and then when the video ends make the video close but it returns to the initial screen. Can some help? I have pasted my code below.
import UIKit
import AVKit
import AVFoundation
class ViewController: UIViewController {
let playerViewController = AVPlayerViewController()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func playButton(_ sender: AnyObject) {
let movieURL = Bundle.main.url(forResource: "video", withExtension: "mp4")!
let player = AVPlayer(url: movieURL as URL)
playerViewController.player = player
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerViewController.player?.currentItem)
self.present(playerViewController, animated: true) {
self.playerViewController.player!.play()
}
}
#objc func playerDidFinishPlaying(note: NSNotification) {
self.playerViewController.dismiss(animated: true)
}
}
What do you mean by "finished"?
is it mean the video is ended or user close the viewcontroller or other?
for when the video finish, you need to use NotificationCenter
func playVideo(url: URL) {
let playerItem = AVPlayerItem(asset: AVURLAsset(url: someVideoUrl))
NotificationCenter.default.addObserver(self, selector: #selector(playerItemDidPlayToEndTime), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerItem)
self.player.replaceCurrentItem(with: playerItem)
self.player.play()
}
func playerItemDidPlayToEndTime() {
// load next video or something
}
for when user close AVPlayerViewController,
you can check AVPlayerViewControllerDelegate , it have several method that may fulfill your need
Self-teaching novice here.
My end goal:
iOS/Mac app that loads a directory of PDFs, searches each for an array of strings, and lists which PDFs contain which strings where.
Problem in prototyping for only one PDF:
I receive a perplexing nil from loading a chosen PDF, running .beginFindStrings(["and", "the"], withOptions: .caseInsensitive) and waiting for the Notification .PDFDocumentDidEndFind to check [PDFSelection] .
That shouldn't be. Memory shows the PDF is loaded. Am I doing something wrong with threads? I think I've followed the async advice here: PDFKit background search
Code
import UIKit
import MobileCoreServices
import PDFKit
class ViewController: UIViewController, UIDocumentPickerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
var matchesFound: PDFSelection?
#IBOutlet weak var resultsLabel: UILabel!
#IBAction func importPDF(_ sender: Any) {
let picker = UIDocumentPickerViewController(documentTypes: [kUTTypePDF as String], in: .import)
picker.delegate = self
picker.allowsMultipleSelection = false
self.present(picker, animated: true)
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard urls.count == 1 else {return}
let data = try! Data(contentsOf: urls[0])
let subjectPDF = PDFDocument.init(data: data)
guard subjectPDF!.isLocked == false else {return}
subjectPDF!.beginFindStrings(["the", "and"], withOptions: .caseInsensitive)
NotificationCenter.default.addObserver(self, selector: #selector(onDidFindMatch(_:)), name: Notification.Name.PDFDocumentDidEndFind, object: nil)
}
#objc func onDidFindMatch(_ notification: Notification) {
resultsLabel.text = "\(String(describing: matchesFound?.string))"
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
dismiss(animated: true, completion: nil)
}
}
Code with Markup
import UIKit
import MobileCoreServices
import PDFKit
class ViewController: UIViewController, UIDocumentPickerDelegate {
override func viewDidLoad() {
super.viewDidLoad()
}
//Array of PDFSelection search results
var matchesFound: PDFSelection?
//Temporary display for search result strings
#IBOutlet weak var resultsLabel: UILabel!
//Choose a PDF to import, temporarily limited to one
#IBAction func importPDF(_ sender: Any) {
let picker = UIDocumentPickerViewController(documentTypes: [kUTTypePDF as String], in: .import)
picker.delegate = self
picker.allowsMultipleSelection = false
self.present(picker, animated: true)
}
//Load the picked PDF as subjectPDF, if unlocked
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard urls.count == 1 else {return}
let data = try! Data(contentsOf: urls[0])
let subjectPDF = PDFDocument.init(data: data)
guard subjectPDF!.isLocked == false else {return}
//Find temporary array of strings
subjectPDF!.beginFindStrings(["the", "and"], withOptions: .caseInsensitive)
//Trigger results readout upon search competion
NotificationCenter.default.addObserver(self, selector: #selector(onDidFindMatch(_:)), name: Notification.Name.PDFDocumentDidEndFind, object: nil)
}
//Readout found strings to temporary label
#objc func onDidFindMatch(_ notification: Notification) {
resultsLabel.text = "\(String(describing: matchesFound?.string))"
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
dismiss(animated: true, completion: nil)
}
}
The question was asked 7 months ago though, I hope you already found the solution.
Anyway the solution for your problem:
1- Move the line below to the viewDidLoad(), because you are adding an observer after triggering the beginFindString() method.
NotificationCenter.default.addObserver(self, selector: #selector(onDidFindMatch(_:)), name: Notification.Name.PDFDocumentDidEndFind, object: nil)
2- You are never assigning any value to matchesFound variable, so it's always nil.
3- To get the matches from beginFindString method, you need to add an observer for PDFDocumentDidFindMatch and get the data from userInfo instead of PDFDocumentDidEndFind.
PDFDocumentDidEndFind observer will be called when searching has been finished, you can use this observer for removing you loading view for instance.
Here is a sample code of the correct implementation:
var matchesFound = [PDFSelection]()
// MARK: Life cycle
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(didFindMatch(_:)), name: NSNotification.Name.PDFDocumentDidFindMatch, object: nil)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
// This method will get called every-time a match has been found.
#objc private func didFindMatch(_ sender: Notification) {
guard let selection = sender.userInfo?["PDFDocumentFoundSelection"] as? PDFSelection else { return }
self.matchesFound.append(selection)
}
I needed to write an iOS App which counts down by pressing the Up Volume Key on an iPhone or iPad. Therefore I used some advice from here to use AVAudioSession and observe the "outputVolume" key.
Here you can find the code of my ViewController:
import UIKit
import MediaPlayer
class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
#IBOutlet weak var chickenLabel: UILabel!
let audioSession = AVAudioSession.sharedInstance()
var maxHendl:Int = 100
var istHendl:Int = 100
var isVolumeChanged = false
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
listenVolumeButton()
removeVolumeView()
}
func listenVolumeButton() {
do {
try audioSession.setActive(true)
}
catch {
print(error.localizedDescription)
}
audioSession.addObserver(self, forKeyPath: "outputVolume", options: .new, context: nil)
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "outputVolume" {
if isVolumeChanged == false {
// Set Volume to 50%
MPVolumeView().subviews.filter{NSStringFromClass($0.classForCoder) == "MPVolumeSlider"}.first as? UISlider)?.setValue(0.5, animated: false)
//do some Counting
}
}
}
func removeVolumeView() {
let volumeView: MPVolumeView = MPVolumeView(frame: CGRect.zero)
view.addSubview(volumeView)
}
}
Everything works as it should after starting the App for the first time. When I now press the Home Button and return back to the App the Events of pressing the volume buttons are not captured and the MPVolumeWindow is displayed again.
Can somebody help me to solve this issue?
Regards
Armin
When you come back from being in the background, your audio session is no longer active. You need to activate it again.
I am making a simple iPad app to play a movie when a button is pressed. The movie plays and when the movie is finished I want to close AVPlayerView so it goes back to the main screen.
Currently when the video finishes it stays on the last frame.
My ViewController.Swift at the moment.
import UIKit
import AVKit
import AVFoundation
class ViewController: UIViewController {
//MARK : Properties
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
//MARK: Actions
#IBAction func playButton(_ sender: AnyObject) {
let movieURL = Bundle.main.url(forResource: "ElephantSeals", withExtension: "mov")!
let player = AVPlayer(url: movieURL as URL)
let playerViewController = AVPlayerViewController()
playerViewController.player = player
self.present(playerViewController, animated: true) {
playerViewController.player!.play()
}
// player.actionAtItemEnd = playerViewController.dismiss(animated: true)
}
}
As you can see, I think there might be something in actionAtItemEnd, but I'm not sure how to implement it.
Thank you.
This is working code in swift 5.3 and iOS 14.2, try this and let me know...:)
import UIKit
import AVKit
import AVFoundation
class ViewController: UIViewController {
let playerViewController = AVPlayerViewController()
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func playButton(_ sender: AnyObject) {
let movieURL = Bundle.main.url(forResource: "ElephantSeals", withExtension: "mp4")!
let player = AVPlayer(url: movieURL as URL)
playerViewController.player = player
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerViewController.player?.currentItem)
self.present(playerViewController, animated: true) {
self.playerViewController.player!.play()
}
}
#objc func playerDidFinishPlaying(note: NSNotification) {
self.playerViewController.dismiss(animated: true)
}
}
You can download sample project for same from here
https://github.com/deepakiosdev/AVPlayerViewControllerDemo
Swift 4
let playerController = AVPlayerViewController()
private func playVideo() {
guard let path = Bundle.main.path(forResource: "p810", ofType:"mp4") else {
debugPrint("video.m4v not found")
return
}
let player = AVPlayer(url: URL(fileURLWithPath: path))
playerController.player = player
NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: playerController.player?.currentItem)
present(playerController, animated: true) {
player.play()
}
}
#objc func playerDidFinishPlaying(note: NSNotification) {
playerController.dismiss(animated: true, completion: nil)
}
Using NSNotificationCenter you can do this .
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.playerDidFinishPlaying), name: NSNotification.Name.AVPlayerItemDidPlayToEndTime, object: videoPlayer!.currentItem)
#objc func playerDidFinishPlaying(note: NSNotification) {
// here you can do your dismiss controller logic
AVPlayerViewController.dismiss(animated: true)
print("Video Finished")
}
here is objective c code
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(nextVideo:) name:AVPlayerItemDidPlayToEndTimeNotification object:playerViewController.player.currentItem];
Invoke AVPlayerViewControllerDelegate.
In viewDidLoad initialize the delegate and implement this method
func playerViewControllerDidStopPictureInPicture(AVPlayerViewController) {
AVPlayerViewController.dismiss(animated: true)
}
https://developer.apple.com/reference/avkit/avplayerviewcontrollerdelegate