使用SwiftUI和AVFoundation将音频文件上载到Firebase

使用SwiftUI和AVFoundation将音频文件上载到Firebase,firebase,swiftui,avfoundation,firebase-storage,avkit,Firebase,Swiftui,Avfoundation,Firebase Storage,Avkit,我想将音频文件上载到Firebase存储,然后将其取出播放。我尝试将的路径存储在全局变量中: var fileURL: URL? 目前,我使用AVFoundation录制音频的代码如下: func startRecording() { let recordingSession = AVAudioSession.sharedInstance() do { try recordingSession.setCatego

我想将音频文件上载到Firebase存储,然后将其取出播放。我尝试将的路径存储在全局变量中:

var fileURL: URL?
目前,我使用AVFoundation录制音频的代码如下:

func startRecording() {
            let recordingSession = AVAudioSession.sharedInstance()
        
        do {
            try recordingSession.setCategory(.playAndRecord, mode: .default)
            try recordingSession.setActive(true)
        }
        catch {
            print("Failed to set up recording session")
        }
        
        let documentPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        
        let audioFilename = documentPath.appendingPathComponent("\(Date().toString(dateFormat: "dd-MM-YY_'at'_HH:mm:ss")).m4a")
        
        self.fileURL = audioFilename
        
        let settings = [
                    AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
                    AVSampleRateKey: 12000,
                    AVNumberOfChannelsKey: 1,
                    AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
                ]
        
        do {
            audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings)
            audioRecorder.record()
            
            recording = true
            
        }
        catch {
            print("Could not start recording with error: \(error)")
        }
    }
在此之后,我想停止录音,但也上传到文件到Firebase。目前,我已经编写了这段代码,它参考了基于本地参考点上传文件的Firebase文档。我不知道如何访问音频文件的数据,也不知道什么是直接上传到Firebase存储的好方法。以下是完整的ViewModel代码:

import Foundation
import AVFoundation
import SwiftUI
import Combine
import Firebase

class VoiceViewModel : NSObject ,ObservableObject {
    
    override init() {
        super.init()
        fetchRecordings()
    }
    
    
    var fileURL: URL?
    
    let objectWillChange = PassthroughSubject<VoiceViewModel, Never>()
    
    var audioRecorder: AVAudioRecorder!
    
    var recordings = [Recording]()
    
    
    
    @Published var recording = false {
            didSet {
                objectWillChange.send(self)
            }
        }
    
    func startRecording() {
            let recordingSession = AVAudioSession.sharedInstance()
        
        do {
            try recordingSession.setCategory(.playAndRecord, mode: .default)
            try recordingSession.setActive(true)
        }
        catch {
            print("Failed to set up recording session")
        }
        
        let documentPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
        
        let audioFilename = documentPath.appendingPathComponent("\(Date().toString(dateFormat: "dd-MM-YY_'at'_HH:mm:ss")).m4a")
        
        self.fileURL = audioFilename
        
        let settings = [
                    AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
                    AVSampleRateKey: 12000,
                    AVNumberOfChannelsKey: 1,
                    AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
                ]
        
        do {
            audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings)
            audioRecorder.record()
            
            recording = true
            
        }
        catch {
            print("Could not start recording with error: \(error)")
        }
    }
    
    func stopRecording() {
        audioRecorder.stop()
        recording = false
        
        let storageRef = Storage.storage().reference()
        
        let localfile = self.fileURL ?? URL(string: "")
        
        let fileRef = storageRef.child("images/try.m4a")
        
        print(self.fileURL?.absoluteURL)
        let uploadTask = fileRef.putFile(from: localfile!, metadata: nil) { metaData, err in
            guard let metadata = metaData else { return }
            
            if let err = err {
                print(err.localizedDescription)
                return
            }
            
            fileRef.downloadURL { (url, err) in
                guard let downloadUrl = url else { return }
                
                print(downloadUrl)
            }
            
        }
        
        
        fetchRecordings()
    }
       
    
    func fetchRecordings() {
            recordings.removeAll()
            
            let fileManager = FileManager.default
            let documentDirectory = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
            let directoryContents = try! fileManager.contentsOfDirectory(at: documentDirectory, includingPropertiesForKeys: nil)
            for audio in directoryContents {
                let recording = Recording(fileURL: audio, createdAt: getCreationDate(for: audio))
                recordings.append(recording)
                
                recordings.sort(by: { $0.createdAt.compare($1.createdAt) == .orderedAscending})
                objectWillChange.send(self)
            }
        }    
}
<代码>导入基础 进口AVF基金会 导入快捷键 进口联合收割机 进口火基 类VoiceViewModel:NSObject,ObservableObject{ 重写init(){ super.init() fetchRecordings() } var fileURL:URL? let objectWillChange=PassthroughSubject() var录音机:AVAudioRecorder! var记录=[记录]() @已发布的var记录=false{ 迪塞特{ objectWillChange.send(self) } } func startRecording(){ 让recordingSession=AVAudioSession.sharedInstance() 做{ 尝试录制Session.setCategory(.playAndRecord,模式:。默认值) 尝试recordingSession.setActive(真) } 抓住{ 打印(“设置录制会话失败”) } 让documentPath=FileManager.default.URL(对于:.documentDirectory,在:.userDomainMask中)[0] 让audioFilename=documentPath.appendingPathComponent(\(Date().toString(dateFormat:“dd-MM-YY”at“u HH:MM:ss”).m4a) self.fileURL=audioFilename 让设置=[ AVFormatIDKey:Int(kaudioformampeg4aac), AVE密钥:12000, AVNumberOfChannelsKey:1, AVEncoderAudioQualityKey:AVAudioQuality.high.rawValue ] 做{ audioRecorder=试用AVAudioRecorder(url:audioFilename,设置:设置) 录音机 录音=真 } 抓住{ 打印(“无法开始录制,错误:\(错误)”) } } 函数停止录制(){ 录音机 录音=假 让storageRef=Storage.Storage().reference() 让localfile=self.fileURL??URL(字符串:“”) 让fileRef=storageRef.child(“images/try.m4a”) 打印(self.fileURL?.absoluteURL) 让uploadTask=fileRef.putFile(from:localfile!,metadata:nil){metadata,err-in guard let metadata=元数据else{return} 如果让err=err{ 打印(错误本地化描述) 返回 } fileRef.downloadURL{(url,err)位于 guard let downloadUrl=url else{return} 打印(下载URL) } } fetchRecordings() } func fetchRecordings(){ recordings.removeAll() 让fileManager=fileManager.default 让documentDirectory=fileManager.URL(对于:.documentDirectory,在:.userDomainMask中)[0] 让directoryContents=try!fileManager.contentsOfDirectory(位于:documentDirectory,包括属性forkeys:nil) 用于directoryContents中的音频{ 让录制=录制(fileURL:audio,createdAt:getCreationDate(for:audio)) 录音。追加(录音) recordings.sort(按:{$0.createdAt.compare($1.createdAt)==.orderedAscending}) objectWillChange.send(self) } } }
您似乎已经编写了上载文件的代码。你能澄清问题在哪里,或者你在哪里得到了意想不到的结果吗?另外,请注意,您不需要在
@Published
属性上使用
didSet{objectWillChange.send(self)}
——这只在SwiftUI 1.0的测试版期间才需要。当我调用startRecording函数时,我没有得到任何错误。调用stopRecording函数时,出现以下错误:AddInstanceForFactory:没有为id注册的工厂。我不确定问题出在哪里。当我打印出self.fileURL函数时,我得到了本地路径。你是这样搜索的吗?这个问题和答案似乎解决了这个问题:是的,这是关于AVPlayer的。尝试将文件上载到Firebase时出错。“audioRecorder.stop()”函数来自“AVAudioRecorder”类。而且音频文件可以毫无问题地保存在设备中。但是,该文件不会上载到Firebase存储。