Swift调用AVAudioPlayer播放Firebase音频触发NSInvalidArgumentException异常
Firebase存储MP3播放崩溃问题解决
调用自定义AudioManager类的playAudio()方法播放Firebase存储的MP3时,在代码行player = try AVAudioPlayer(contentsOf: url)触发崩溃,错误信息如下:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSTaggedPointerString getCharacters:range:]: Range {0, 12} out of bounds; string length 2'
*** First throw call stack:
问题代码
class AudioManager { static let instance = AudioManager() var player: AVAudioPlayer? func playAudio() { guard let url = URL(string: "gs://quranburma.appspot.com/x.mp3") else { return } do { player = try AVAudioPlayer(contentsOf: url) player?.play() } catch let error { print("error playing audio. \(error.localizedDescription)") } } func stopAudio() { player?.pause() } }
错误原因
AVAudioPlayer不支持直接解析Firebase Storage的gs://协议链接,它仅能处理本地文件URL或HTTP/HTTPS格式的远程URL。直接传入gs://链接会导致内部字符串处理逻辑出错,触发越界异常。
解决方案
方案1:获取HTTPS下载链接播放
通过Firebase Storage SDK获取文件的HTTPS下载链接,再传入AVAudioPlayer:
class AudioManager { static let instance = AudioManager() var player: AVAudioPlayer? func playAudio() { // 创建Firebase Storage引用 let storageRef = Storage.storage().reference(forURL: "gs://quranburma.appspot.com/x.mp3") // 获取HTTPS下载链接 storageRef.downloadURL { [weak self] url, error in guard let self = self else { return } if let error = error { print("获取下载链接失败:\(error.localizedDescription)") return } guard let downloadUrl = url else { return } // 初始化AVAudioPlayer并播放 do { self.player = try AVAudioPlayer(contentsOf: downloadUrl) self.player?.play() } catch let error { print("播放音频错误:\(error.localizedDescription)") } } } func stopAudio() { player?.pause() } }
方案2:下载文件到本地后播放
如果需要离线播放,可将文件下载到本地文档目录,再使用本地URL初始化AVAudioPlayer:
class AudioManager { static let instance = AudioManager() var player: AVAudioPlayer? func playAudio() { let storageRef = Storage.storage().reference(forURL: "gs://quranburma.appspot.com/x.mp3") // 获取本地文档目录路径 guard let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { print("无法获取本地目录") return } let localFileUrl = documentsDir.appendingPathComponent("x.mp3") // 下载文件到本地 let downloadTask = storageRef.write(toFile: localFileUrl) { [weak self] url, error in guard let self = self else { return } if let error = error { print("下载音频失败:\(error.localizedDescription)") return } guard let localUrl = url else { return } // 本地文件播放 do { self.player = try AVAudioPlayer(contentsOf: localUrl) self.player?.play() } catch let error { print("播放音频错误:\(error.localizedDescription)") } } // 可选:监听下载进度 downloadTask.observe(.progress) { snapshot in let percentComplete = 100.0 * Double(snapshot.progress!.completedUnitCount) / Double(snapshot.progress!.totalUnitCount) print("下载进度:\(percentComplete)%") } } func stopAudio() { player?.pause() } }
内容的提问来源于stack exchange,提问作者Zin Win Htet
相关产品推荐
相关产品推荐

