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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 12:15:22