Search code examples
iosswiftswift3avplayernsfilemanager

Play an mp3 file downloaded to filemanager using AVPlayer


I'm working on a project in swift3 and I have a particular UIViewController to download an mp3 to my filemanager and using that path saved I wants to play an mp3 using AVPlayer. My code doesn't work, I think Im missing something. How would I achieve this?. My code to download the file to the filemanager as below

func downloadSong() {

    if let audioUrl = URL(string: "https://www.googleapis.com/download/storage/v1/b/feisty-beacon-159305.appspot.com/o/Aal%20Izz%20Well%20-%20Remix(MyMp3Song).mp3?generation=1490097740630162&alt=media") {

        // then lets create your document folder url
        let documentsDirectoryURL =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!//since it sys first this may  only plays the first item

        // destination file url
        let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
        print("destinationUrl is :",destinationUrl)

        // to check if it exists before downloading it
        if FileManager.default.fileExists(atPath: destinationUrl.path) {
            print("The file already exists at path")
             self.dest = destinationUrl.path
            // if the file doesn't exist
        } else {

            // you can use NSURLSession.sharedSession to download the data asynchronously
            URLSession.shared.downloadTask(with: audioUrl, completionHandler: { (location, response, error) -> Void in
                guard let location = location, error == nil else { return }
                do {
                    // after downloading your file you need to move it to your destination url
                    try FileManager.default.moveItem(at: location, to: destinationUrl)

                    print("file path is :",destinationUrl.path)
                    print("File moved to documents folder")
                } catch let error as NSError {
                    print(error.localizedDescription)
                }
            }).resume()
        }
    }
}

And once I save that file, using its file path which is "destinationUrl.path" I initiate my player as bellow in a different UIViewController. As for now I have hardcoded the path I save. The code as bellow.

    override func viewDidLoad() {
        super.viewDidLoad()
    //path I have saved in file manager is set to the url
    let url = NSURL.fileURL(withPath:"/Users/auxenta/Library/Developer/CoreSimulator/Devices/F3840294-04AA-46BE-9E46-4342452AFB69/data/Containers/Data/Application/670C0EA1-B375-498E-8847-8707D391D7BF/Documents/Aal Izz Well - Remix(MyMp3Song).mp3") as NSURL

        self.playerItem = AVPlayerItem(url: url as URL)
        self.player=AVPlayer(playerItem: self.playerItem!)
        let playerLayer=AVPlayerLayer(player: self.player!)
        playerLayer.frame = CGRect(x: 0, y: 0, width: 10, height: 50) // actually this player layer is not visible
        self.view.layer.addSublayer(playerLayer)
    }

@IBAction func playBtnPressed(_ sender: Any) {
         if player?.rate == 0 // this means if its not playing
         {
            player!.play()
            print("playing")
            playbutton.setImage(UIImage(named: "pausebutton"), for: UIControlState.normal)

            //trackTime
            trackTime()
       } else {
            // getFileFromFieManager()
            print("pause")
            player!.pause()
            playbutton.setImage(UIImage(named: "playbutton"), for: UIControlState.normal)
      }

}

Solution

  • Your problem is the URL set to the AVPlayer. In fact hardcoding a path in iOS doesn't work, it can change at any time.

    You need to use code it the same way as you destinationUrl:

        if let audioUrl = URL(string: "https://www.googleapis.com/download/storage/v1/b/feisty-beacon-159305.appspot.com/o/Aal%20Izz%20Well%20-%20Remix(MyMp3Song).mp3?generation=1490097740630162&alt=media") {
                    
                    
              let documentsDirectoryURL =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!//since it sys first this may  only plays the first item
                    
               // destination file url
               let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
               print("destinationUrl is :",destinationUrl)
                
               self.playerItem = AVPlayerItem(url: destinationUrl)
               self.player=AVPlayer(playerItem: self.playerItem!)
               let playerLayer=AVPlayerLayer(player: self.player!)
      
    
                             .
                             .
                             .
    }
    

    Normally it should work. Hope it helps.