You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS音频下载存文件后无法播放:代码及权限问题排查

问题排查与修复方案

1. 核心问题:AVPlayer 被立即释放

你在playAudio方法里创建的AVPlayer是局部变量,DispatchQueue.main.async闭包执行完毕后,这个实例会被系统立即回收,根本来不及启动播放。

修复方法:在ViewController类中声明全局属性强持有AVPlayer:

class YourViewController: UIViewController {
    // 全局强引用,避免被释放
    var audioPlayer: AVPlayer?
    
    // ... 其他原有代码
    
    func playAudio(fromData audioData: Data, url: URL) {
        let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let audioFileURL = documentsDirectoryURL.appendingPathComponent(url.lastPathComponent)
        
        do {
            try audioData.write(to: audioFileURL)
            DispatchQueue.main.async {
                let audioPlayerItem = AVPlayerItem(url: audioFileURL)
                // 赋值给全局属性,强持有
                self.audioPlayer = AVPlayer(playerItem: audioPlayerItem)
                self.audioPlayer?.play()
            }
        } catch {
            print("Error writing audio data to file: \(error.localizedDescription)")
        }
    }
}

2. 权限配置完全错误

你配置的NSFileProviderExtension是文件扩展相关权限,和当前的音频下载、播放需求完全无关:

  • 写入App的Documents目录不需要额外权限,该目录默认支持读写
  • 若使用HTTP链接下载(你当前用的是HTTPS,无需配置),需在Info.plist中添加NSAppTransportSecurity配置允许非HTTPS请求
  • 如需后台播放音频,需在Info.plist的UIBackgroundModes中添加audio项

3. 未处理网络请求失败场景

你的dataTask闭包只处理了data存在的情况,完全忽略了网络错误、响应异常的场景,可能下载早已失败但你没有察觉:

session.dataTask(with: request) { data, response, error in
    // 先处理错误
    if let error = error {
        print("下载失败: \(error.localizedDescription)")
        return
    }
    // 校验HTTP响应状态
    guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
        print("响应异常: \(response?.description ?? "无响应")")
        return
    }
    // 校验数据存在
    guard let data = data else {
        print("无返回数据")
        return
    }
    // 后续处理逻辑
    DispatchQueue.main.async {
        self.savedFiles[url.absoluteString] = data
        self.playAudio(fromData: data, url: url)
    }
}.resume()

4. 新增文件写入与播放状态校验

可以在写入文件后校验文件完整性,同时监听AVPlayer的状态,确认音频是否成功加载:

do {
    try audioData.write(to: audioFileURL)
    // 校验文件是否写入成功
    if FileManager.default.fileExists(atPath: audioFileURL.path) {
        let fileSize = try FileManager.default.attributesOfItem(atPath: audioFileURL.path)[.size] as? Int64
        print("文件写入成功,大小: \(fileSize ?? 0)字节")
    }
    DispatchQueue.main.async {
        let audioPlayerItem = AVPlayerItem(url: audioFileURL)
        self.audioPlayer = AVPlayer(playerItem: audioPlayerItem)
        
        // 监听音频加载状态
        audioPlayerItem.addObserver(self, forKeyPath: "status", options: [.new], context: nil)
        self.audioPlayer?.play()
    }
} catch {
    print("写入文件失败: \(error.localizedDescription)")
}

// 状态监听方法
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if let playerItem = object as? AVPlayerItem, keyPath == "status" {
        switch playerItem.status {
        case .readyToPlay:
            print("音频准备完成")
        case .failed:
            print("音频加载失败: \(playerItem.error?.localizedDescription ?? "未知错误")")
        case .unknown:
            print("音频状态未知")
        @unknown default:
            break
        }
    }
}

内容的提问来源于stack exchange,提问作者kesape

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 00:47:30