swiftxcodeavplayeravplayeritem

AVPlayer class to be used for Multiple View Controllers


I am using AVPlayer item to play live streams (Radio App). Everything seems to be working, however, the entire code is under one View Controller i.e PlayerViewController : UIViewController. Since I will add more functionality to the app and do not want to repeat all the methods being used for AVPlayer. How can I create a Swift Class for AVPlayer with all required methods and keep using that class instance on multiple pages (future view controllers) of my app?

Here is the code, which loads to ViewDid Load(). Functionality like Remote Commands will be added to it later on. I don't want to repeat the code for separate view controllers performing the same task.

   func configurePlayer(){
        do {
            try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
            print("AVAudioSession Category Playback OK")
            do {
                try AVAudioSession.sharedInstance().setActive(true)
                print("AVAudioSession is Active")

            } catch let error as NSError {
                print(error.localizedDescription)
            }
        } catch let error as NSError {
            print(error.localizedDescription)
        }
        guard let url = URL(string: station!.url!) else {return}
        let playerItem = AVPlayerItem(url: url)
        player = AVPlayer(playerItem: playerItem)  

    }
 

Some Other methods to this class will be

func togglePlayer() {
    if player?.rate != 0 {
        player?.pause()
        self.playButton.setBackgroundImage(UIImage(systemName: "play.circle"), for: .normal)
    } else {
        player?.play()
        self.playButton.setBackgroundImage(UIImage(systemName: "stop"), for: .normal)
    }
}

//Method 1{...}
//Method 2 {...}

Solution

  • You don't need to have your class inherit from AVPlayer since you probably wont be using all the features it has to offer so just create a normal class.

    Also, this will vary by a lot depending on your use case or implementation so I will just provide a sample for you to experiment with.

    class UniversalAVPlayer {
        
        var player: AVPlayer?
        
        init(url: URL?) {
            configurePlayer(url: url)
            allFeatureConfigs()
        }
        
        func configurePlayer(url: URL?) {
            do {
                try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback)
                print("AVAudioSession Category Playback OK")
                do {
                    try AVAudioSession.sharedInstance().setActive(true)
                    print("AVAudioSession is Active")
                    
                } catch let error as NSError {
                    print(error.localizedDescription)
                }
            } catch let error as NSError {
                print(error.localizedDescription)
            }
            guard let url = url else {return}
            let playerItem = AVPlayerItem(url: url)
            player = AVPlayer(playerItem: playerItem)
            
        }
        
        func allFeatureConfigs() {
            //add any configurations you want to add in the future here.
        }
        
    }
    

    and you should create a delegate to help you with methods like your togglePlayer method:

    func togglePlayer() {
        if player?.rate != 0 {
            player?.pause()
            self.delegate?.changeImageForPlayStatus(image : UIImage(systemName: "play.circle"))
        } else {
            player?.play()
            self.delegate?.changeImageForPlayStatus(image: UIImage(systemName: "stop"))
        }
    }
    

    And for example change your background image in your VC when the delegate method is called using the image it provides you.

    Since you won't be setting these functions private you will be able to use them from the instance you create:

    let player = UniversalAVPlayer(url: url) //imagine url is an actual URL
    //your config methods will run instantly when you create this instance since they are called at initialization
    
    //Call your methods like this when ever you need.
    player.togglePlayer()