iOS音频播放器无法播放Firestore URL音频,报OSStatus错误2003334207
问题描述
- 本地录制存储的音频可正常播放,上传至Firebase Storage后,音频链接在Chrome中能正常播放,但使用自定义AVAudioPlayer播放时报错:
播放失败。操作无法完成。(OSStatus错误2003334207。) - 尝试为URL添加/移除
.m4a后缀均无法解决问题 - 测试URL:
- https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/audio%2F60787BCB-DEFE-4743-BF05-A2EAF24C0F28.m4a?alt=media&token=a29c8a9a-ce16-4240-9af1-5aefcac8a824.m4a
- https://firebasestorage.googleapis.com:443/v0/b/hustle-85b6c.appspot.com/o/audio%2F60787BCB-DEFE-4743-BF05-A2EAF24C0F28.m4a?alt=media&token=a29c8a9a-ce16-4240-9af1-5aefcac8a824
问题原因
OSStatus错误2003334207对应AVAudioPlayer的核心限制:它仅支持播放本地文件或已加载到内存的音频数据,不支持直接流式播放网络URL。浏览器能正常播放是因为内置了支持网络流的播放器,而AVAudioPlayer不具备该能力。
解决方案
提供两种可行修复方案:
方案一:改用AVPlayer(推荐,支持流式播放)
替换原有的AVAudioPlayer为AVPlayer,它原生支持网络音频流播放,无需提前下载文件。修改后的代码示例:
import SwiftUI import AVFoundation public final class AudioPlayer: NSObject, ObservableObject { @Published public var isPlaying = false @Published public var currentTime: Int = 0 @Published public var fileDuration: TimeInterval = 0 private var player: AVPlayer? private var timeObserver: Any? static let shared = AudioPlayer() func startPlayback(audio: URL) { // 直接使用传入的原始URL,无需手动添加后缀 let playerItem = AVPlayerItem(url: audio) player = AVPlayer(playerItem: playerItem) do { try AVAudioSession.sharedInstance().setCategory(.playback, options: .duckOthers) try AVAudioSession.sharedInstance().setActive(true) } catch { print("音频会话设置失败:\(error.localizedDescription)") return } player?.play() isPlaying = true // 监听播放时长和进度 fileDuration = playerItem.duration.seconds.rounded() currentTime = Int(fileDuration) timeObserver = player?.addPeriodicTimeObserver(forInterval: CMTimeMakeWithSeconds(1, preferredTimescale: 1), queue: .main) { [weak self] time in guard let self = self else { return } let elapsed = Int(time.seconds) self.currentTime = Int(self.fileDuration) - elapsed } // 监听播放结束 NotificationCenter.default.addObserver(self, selector: #selector(playerDidFinishPlaying), name: .AVPlayerItemDidPlayToEndTime, object: playerItem) } @objc private func playerDidFinishPlaying() { stopPlayback() } public func stopPlayback() { player?.pause() player = nil if let observer = timeObserver { player?.removeTimeObserver(observer) timeObserver = nil } isPlaying = false currentTime = Int(fileDuration) NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: nil) } }
方案二:先下载音频到本地再用AVAudioPlayer播放
如果必须保留AVAudioPlayer,可以先将网络音频下载到临时目录,再读取本地文件路径播放:
func startPlayback(audio: URL) { let task = URLSession.shared.dataTask(with: audio) { [weak self] data, response, error in guard let self = self, let data = data, error == nil else { print("下载失败:\(error?.localizedDescription ?? "未知错误")") return } // 创建临时文件路径 let tempDir = NSTemporaryDirectory() let tempFile = tempDir + "temp_audio.m4a" let tempURL = URL(fileURLWithPath: tempFile) do { try data.write(to: tempURL) DispatchQueue.main.async { do { try AVAudioSession.sharedInstance().setCategory(.playback, options: .duckOthers) try AVAudioSession.sharedInstance().setActive(true) self.audioPlayer = try AVAudioPlayer(contentsOf: tempURL) self.audioPlayer.volume = 1.0 self.audioPlayer.delegate = self self.audioPlayer.play() withAnimation { self.isPlaying = true } self.fileDuration = self.audioPlayer.duration.rounded() self.startMonitoring() } catch { print("播放失败:\(error.localizedDescription)") } } } catch { print("保存临时文件失败:\(error.localizedDescription)") } } task.resume() }
额外注意点
- 原代码中手动给URL添加
.m4a后缀是错误操作,会导致URL无效(比如第一个测试URL末尾已多了一个.m4a),直接使用传入的原始URL即可。 - 确保App已开启网络权限(在
Info.plist中确认Firebase Storage的URL为HTTPS,iOS默认允许HTTPS请求;若需HTTP请求需配置NSAppTransportSecurity)。
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

