如何下载并保存音频文件然后快速播放?

Posted

技术标签:

【中文标题】如何下载并保存音频文件然后快速播放?【英文标题】:How to download and save an audio file and then play it in swift? 【发布时间】:2019-05-17 22:04:20 【问题描述】:

我正在尝试从 Internet 下载音频文件并将其保存到手机上。这是下载功能:

func download() 
    if let audioUrl = downloadUrl 

        // then lets create your document folder url
        let documentsDirectoryURL =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

        // lets create your destination file url
        let destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)
        print(destinationUrl)

        // to check if it exists before downloading it
        if FileManager.default.fileExists(atPath: destinationUrl.path) 
            print("The file already exists at 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 moved to documents folder")
                 catch let error as NSError 
                    print(error.localizedDescription)
                
            ).resume()
        
    

然后,在我关闭并打开应用程序后,我使用以下函数检索 url 并使用 AVPlayer 播放它:

func getUrl2() 
    if let audioUrl = downloadUrl 

        // then lets create your document folder url
        let documentsDirectoryURL =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!

        destinationUrl = documentsDirectoryURL.appendingPathComponent(audioUrl.lastPathComponent)

        if let u = self.destinationUrl 
            let player = AVPlayer(url: u)
            print(u)
            print("Bouta play")
            print(CMTimeGetSeconds(player.currentItem!.duration))
            player.play()
        
    

不断打印出来的持续时间是“nan”。有没有办法检查音频文件是否真的在下载?或者下载后检索文件是否有问题?提前致谢。

【问题讨论】:

【参考方案1】:

首先,您必须使用以下逻辑检查 URL 是否为空:

if !link.isEmpty
        checkBookFileExists(withLink: link) [weak self] downloadedURL in
            guard let self = self else
                return
            
            play(url: downloadedURL)
        
    

然后 checkBookFileExists 函数会在再次下载之前检查文件是否已经保存:

    func checkBookFileExists(withLink link: String, completion: @escaping ((_ filePath: URL)->Void))
    let urlString = link.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)
    if let url  = URL.init(string: urlString ?? "")
        let fileManager = FileManager.default
        if let documentDirectory = try? fileManager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor:nil, create: false)

            let filePath = documentDirectory.appendingPathComponent(url.lastPathComponent, isDirectory: false)

            do 
                if try filePath.checkResourceIsReachable() 
                    print("file exist")
                    completion(filePath)

                 else 
                    print("file doesnt exist")
                    downloadFile(withUrl: url, andFilePath: filePath, completion: completion)
                
             catch 
                print("file doesnt exist")
                downloadFile(withUrl: url, andFilePath: filePath, completion: completion)
            
        else
             print("file doesnt exist")
        
    else
            print("file doesnt exist")
    

如果该文件不存在,您将使用以下函数下载它:

func downloadFile(withUrl url: URL, andFilePath filePath: URL, completion: @escaping ((_ filePath: URL)->Void))
    DispatchQueue.global(qos: .background).async 
        do 
            let data = try Data.init(contentsOf: url)
            try data.write(to: filePath, options: .atomic)
            print("saved at \(filePath.absoluteString)")
            DispatchQueue.main.async 
                completion(filePath)
            
         catch 
            print("an error happened while downloading or saving the file")
        
    

该功能将保存它,你可以玩它:

  func play(url: URL) 
    print("playing \(url)")

    do 

        audioPlayer = try AVAudioPlayer(contentsOf: url)
        audioPlayer?.prepareToPlay()
        audioPlayer?.delegate = self
        audioPlayer?.play()
        let percentage = (audioPlayer?.currentTime ?? 0)/(audioPlayer?.duration ?? 0)
        DispatchQueue.main.async 
            // do what ever you want with that "percentage"
        

     catch let error 
        audioPlayer = nil
    


【讨论】:

嘿,你检查我的答案了吗? 如果duration 无法解决,(audioPlayer?.duration ?? 0) 会不会给出除以零的错误?

以上是关于如何下载并保存音频文件然后快速播放?的主要内容,如果未能解决你的问题,请参考以下文章

Cordova 播放本地音频文件

如何将音频文件复制到另一个文件

当从 uri 播放视频或音频时,它是流式传输还是完全下载并播放?

如何录制/保存 iPhone 应用程序中正在播放的音频?

录制音频并保存到文档目录后无法使用 AVAudioPlayer 播放音频文件

我正在下载音频文件并将其保存在目录中,但无法播放。 (OSStatus 错误 2003334207。)